├── .changesets ├── .gitkeep └── archive │ └── 2025-06-18-pr-3371.md ├── .codeclimate.yml ├── .cursor ├── prd.md └── rules │ ├── README.md │ ├── php_files.json │ ├── wpgraphql.json │ └── wpgraphql.mdc ├── .distignore ├── .dockerignore ├── .env.dist ├── .github ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ └── feature_request.yml ├── LABELS.md ├── PULL_REQUEST_TEMPLATE.md ├── stale.yml └── workflows │ ├── CHANGESET_GENERATION.md │ ├── MILESTONE_BRANCH_MANAGEMENT.md │ ├── README.md │ ├── RELEASE.md │ ├── build-graphiql.yml │ ├── changeset-generation.yml │ ├── code-quality.yml │ ├── codeql-analysis.yml │ ├── deploy-docker-image.yml │ ├── graphiql-e2e-tests.yml │ ├── lint-pr.yml │ ├── milestone-branch-management.yml │ ├── release.yml │ ├── schema-linter.yml │ ├── testing-integration.yml │ ├── upload-schema-artifact.yml │ └── wordpress-coding-standards.yml ├── .gitignore ├── .nvmrc ├── .wordpress-org ├── banner-1544x500.png ├── banner-772x250.png ├── blueprints │ └── blueprint.json ├── icon-128x128.png ├── icon-256x256.png ├── screenshot-1.jpg └── screenshot-2.jpg ├── .wp-env.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── access-functions.php ├── activation.php ├── bin ├── install-test-env.sh └── run-docker.sh ├── build ├── 113.js ├── 148.js ├── 253.js ├── 260.js ├── 271.js ├── 277.js ├── 331.js ├── 338.js ├── 382.js ├── 385.js ├── 391.js ├── 420.js ├── 482.js ├── 528.js ├── 61.js ├── 627.js ├── 669.js ├── 681.js ├── 77.js ├── 910.js ├── 912.js ├── 924.js ├── 93.js ├── 951.js ├── 983.js ├── app-rtl.css ├── app.asset.php ├── app.css ├── app.js ├── extensions-rtl.css ├── extensions.asset.php ├── extensions.css ├── extensions.js ├── graphiqlAuthSwitch.asset.php ├── graphiqlAuthSwitch.js ├── graphiqlFullscreenToggle-rtl.css ├── graphiqlFullscreenToggle.asset.php ├── graphiqlFullscreenToggle.css ├── graphiqlFullscreenToggle.js ├── graphiqlQueryComposer-rtl.css ├── graphiqlQueryComposer.asset.php ├── graphiqlQueryComposer.css ├── graphiqlQueryComposer.js ├── index.asset.php ├── index.js ├── style-app-rtl.css ├── style-app.css ├── updates-rtl.css ├── updates.asset.php └── updates.css ├── cli ├── README.md └── wp-cli.php ├── codeception.dist.yml ├── composer.json ├── composer.lock ├── constants.php ├── deactivation.php ├── docker-compose.yml ├── docker ├── app.Dockerfile ├── app.entrypoint.sh ├── app.post-setup.sh ├── app.setup.sh ├── testing.Dockerfile └── testing.entrypoint.sh ├── docs ├── authentication-and-authorization.md ├── build-your-first-wpgraphql-extension.md ├── categories-and-tags.md ├── comments.md ├── common-issues.md ├── compatibility-guide.md ├── connections.md ├── contributing.md ├── custom-post-types.md ├── custom-taxonomies.md ├── customizing-wpgraphiql.md ├── debugging.md ├── default-types-and-fields.md ├── docs_nav.json ├── faqs.md ├── graphql-mutations.md ├── graphql-queries.md ├── graphql-resolvers.md ├── hierarchical-data.md ├── images │ ├── application-data-graph.png │ ├── categories-delete-not-allowed.png │ ├── categories-delete-success.png │ ├── categories-mutation-create-not-allowed.png │ ├── categories-mutation-create-success.png │ ├── categories-mutation-update-not-allowed.png │ ├── categories-mutation-update-success.png │ ├── categories-query-by-global-id.png │ ├── categories-query-edges-nodes.png │ ├── categories-query-nodes.png │ ├── comments-mutation-closed-failure.png │ ├── comments-mutation-delete-denied.png │ ├── comments-mutation-delete.png │ ├── comments-mutation-duplicate-error.png │ ├── comments-mutation-not-allowed.png │ ├── comments-mutation-public-user.png │ ├── comments-mutation-restore-not-allowed.png │ ├── comments-mutation-restore-success.png │ ├── comments-mutation-success.png │ ├── comments-query-post.png │ ├── connections-graph.png │ ├── data-graph-category-term-connections.png │ ├── data-graph-category-terms-connection-complex.png │ ├── data-graph-category-terms.png │ ├── data-graph-hello-world.png │ ├── data-graph-query-filter.png │ ├── debugging-graphql-query-logs.png │ ├── debugging-graphql-response.png │ ├── debugging-graphql-trace-log.png │ ├── debugging-graphql-unexpected-token.png │ ├── debugging-output-graphql-debug.png │ ├── debugging-setting-enable-graphql-query-logs.png │ ├── debugging-setting-enable-graphql.png │ ├── debugging-setting-graphql-enable-tracing.png │ ├── debugging-unexpected-token.gif │ ├── extension-graphiql-explorer-custom-type.png │ ├── extension-graphiql-explorer-search.png │ ├── extension-query-custom-field.png │ ├── extension-query-custom-type.png │ ├── extension-wordpress-admin-screen.png │ ├── extension-wordpress-plugin-dir.png │ ├── extension-wordpress-plugin-filename.png │ ├── graphiql-auth-switch.gif │ ├── graphiql-full-window-mode.gif │ ├── graphiql-ide-screenshot.png │ ├── graphiql-query-composer.gif │ ├── interacting-fetch-graphql-from-browser-console-1024x619.gif │ ├── interacting-wordpress-admin-graphiql.png │ ├── intro-graphql-MenuItems.gif │ ├── intro-graphql-fragments.png │ ├── media-query-by-global-id.png │ ├── media-query-by-source-url.png │ ├── media-query-items.png │ ├── media-query-post-featured-image.png │ ├── menus-query-by-global-id.png │ ├── menus-query-by-name.png │ ├── menus-query-filter-location.png │ ├── menus-query-items.png │ ├── mutations-create-post-with-custom-input-example.png │ ├── mutations-custom-input-field-example.png │ ├── plugins-query-authenticated.png │ ├── plugins-query-global-id.png │ ├── plugins-query-id-without-access.png │ ├── plugins-query-unauthenticated.png │ ├── posts-mutation-create-not-allowed.png │ ├── posts-mutation-create-success.png │ ├── posts-mutation-delete-not-allowed.png │ ├── posts-mutation-delete-success.png │ ├── posts-mutation-update-not-allowed.png │ ├── posts-mutation-update-success.png │ ├── posts-query-by-database-id.png │ ├── posts-query-by-global-id.png │ ├── posts-query-by-slug.png │ ├── posts-query-by-uri.png │ ├── posts-query-edges-node.png │ ├── posts-query-filter-by-author.png │ ├── posts-query-filter-by-keyword.png │ ├── posts-query-filter-by-title.png │ ├── posts-query-nodes.png │ ├── quick-graphiql-ide-wordpress.png │ ├── quick-graphiql-ide.png │ ├── quick-graphiql-search-posts.gif │ ├── quick-wp-graphql-first-query.gif │ ├── settings-mutation-authorized.png │ ├── settings-mutation-not-authorized.png │ ├── settings-wordpress-general-page-title.png │ ├── tags-query-by-name.png │ ├── tags-query-by-uri.png │ ├── tags-query-nodes.png │ ├── testing-codeception-screenshot.png │ ├── themes-authenticated-user.png │ ├── themes-not-authenticated-user.png │ ├── users-create-success.png │ ├── users-create-user-unsuccessful.png │ ├── users-delete-success.png │ ├── users-delete-unsuccessful.png │ ├── users-mutation-register-disabled.png │ ├── users-mutation-register-success.png │ ├── users-mutation-reset-password-invalid.png │ ├── users-query-by-global-id.png │ ├── users-query.png │ ├── users-registration-email.png │ ├── users-update-success.png │ ├── users-update-unsuccessful.png │ ├── users-wordpress-new-password.png │ ├── users-wordpress-reset-password.png │ ├── wpgraphql-acf-search-schema.gif │ ├── wpgraphql-nested-query.gif │ ├── wpgraphql-query-100-posts-graphql.png │ ├── wpgraphql-query-100-posts-rest.png │ ├── wpgraphql-query-acf-flex.gif │ ├── wpgraphql-query-batch-postman.png │ ├── wpgraphql-query-github.png │ ├── wpgraphql-query-multiple-resources.png │ ├── wpgraphql-query-types-fields.png │ ├── wpgraphql-wordpress-dashboard.png │ └── wpgraphql-wordpress-rest-api-acf.png ├── interacting-with-wpgraphql.md ├── interfaces.md ├── intro-to-graphql.md ├── intro-to-wordpress.md ├── introduction.md ├── known-limitations.md ├── media.md ├── menus.md ├── performance.md ├── plugins.md ├── posts-and-pages.md ├── quick-start.md ├── security.md ├── settings.md ├── submit-extension.md ├── testing.md ├── themes.md ├── upgrading.md ├── use-with-php.md ├── users.md ├── using-data-from-custom-database-tables.md ├── widgets.md ├── wordpress-as-an-application-data-graph.md ├── wp-graphiql.md ├── wpgraphql-concepts.md ├── wpgraphql-mutations.md ├── wpgraphql-request-lifecycle.md └── wpgraphql-vs-wp-rest-api.md ├── img ├── README.md ├── anatomy-of-request.png ├── graphiql-ide-example.gif ├── logo.png ├── wp-example-web.png ├── wp-graphql-logo-square-512x512.png ├── wp-graphql-logo-square.svg └── wpgraphql-elephant.svg ├── netlify.toml ├── package-lock.json ├── package.json ├── packages ├── README.md ├── extensions │ ├── Extensions.js │ ├── PluginCard.js │ ├── README.md │ ├── index.js │ ├── index.scss │ ├── useInstallPlugin.js │ └── utils.js ├── graphiql-auth-switch │ ├── AuthSwitch.js │ ├── AuthSwitchContext.js │ ├── README.md │ └── index.js ├── graphiql-fullscreen-toggle │ ├── index.js │ └── index.scss ├── graphiql-query-composer │ ├── README.md │ ├── components │ │ ├── AbstractArgView.js │ │ ├── AbstractView.js │ │ ├── AddOperations.js │ │ ├── ArgView.js │ │ ├── Checkbox.js │ │ ├── ErrorBoundary.js │ │ ├── Explorer.js │ │ ├── ExplorerContext.js │ │ ├── ExplorerWrapper.js │ │ ├── FieldView.js │ │ ├── FragmentView.js │ │ ├── InputArgView.js │ │ ├── QueryBuilder.js │ │ ├── RootView.js │ │ └── ScalarInput.js │ ├── index.js │ ├── index.scss │ └── utils │ │ └── utils.js ├── updates │ └── index.scss └── wpgraphiql │ ├── README.md │ ├── app.js │ ├── app.scss │ ├── components │ ├── App │ │ └── App.js │ └── Router │ │ ├── Router.js │ │ └── Router.test.js │ ├── context │ ├── AppContext.js │ └── AppContext.test.js │ ├── data │ └── client.js │ ├── index.js │ ├── screens │ ├── Extensions │ │ └── README.md │ ├── GraphQLDocumentEditor │ │ └── README.md │ ├── GraphiQL │ │ ├── GraphiQL.js │ │ ├── components │ │ │ ├── GraphiQLToolbar.js │ │ │ └── GrapiQLToolbar.test.js │ │ ├── context │ │ │ └── GraphiQLContext.js │ │ ├── style.scss │ │ └── utils │ │ │ └── externalFragments.js │ ├── Help │ │ ├── Help.js │ │ ├── Help.test.js │ │ └── README.md │ ├── Schema │ │ └── README.md │ └── Settings │ │ └── README.md │ └── utils │ ├── fetcher.js │ └── format.js ├── phpcs.xml.dist ├── phpcs └── WPGraphQL │ └── PHPCS │ ├── Sniffs │ ├── Commenting │ │ └── ValidSinceTagSniff.php │ └── Functions │ │ └── VersionParameterSniff.php │ └── ruleset.xml ├── phpstan.neon.dist ├── phpstan ├── class-wp-dependency.php ├── class-wp-post-type.php ├── class-wp-taxonomy.php └── constants.php ├── phpunit.xml.dist ├── readme.txt ├── scripts ├── analyze-changesets.js ├── build.js ├── bump-version.js ├── generate-changeset.js ├── generate-release-notes.js ├── update-changelog.js ├── update-changelogs.js ├── update-readme.js ├── update-since-tags.js ├── update-upgrade-notice.js └── utils │ ├── env.js │ ├── format-pr-body.js │ └── test-changeset-generation.js ├── src ├── Admin │ ├── Admin.php │ ├── AdminNotices.php │ ├── Extensions │ │ ├── Extensions.php │ │ ├── README.md │ │ └── Registry.php │ ├── GraphiQL │ │ ├── GraphiQL.php │ │ └── README.md │ ├── README.md │ ├── Settings │ │ ├── Settings.php │ │ └── SettingsRegistry.php │ └── Updates │ │ ├── PluginsScreenLoader.php │ │ ├── SemVer.php │ │ ├── UpdateChecker.php │ │ ├── Updates.php │ │ └── UpdatesScreenLoader.php ├── AppContext.php ├── Connection │ ├── Comments.php │ ├── MenuItems.php │ ├── PostObjects.php │ ├── Taxonomies.php │ ├── TermObjects.php │ └── Users.php ├── Data │ ├── CommentMutation.php │ ├── Config.php │ ├── Connection │ │ ├── AbstractConnectionResolver.php │ │ ├── CommentConnectionResolver.php │ │ ├── ContentTypeConnectionResolver.php │ │ ├── EnqueuedScriptsConnectionResolver.php │ │ ├── EnqueuedStylesheetConnectionResolver.php │ │ ├── MenuConnectionResolver.php │ │ ├── MenuItemConnectionResolver.php │ │ ├── PluginConnectionResolver.php │ │ ├── PostObjectConnectionResolver.php │ │ ├── README.md │ │ ├── TaxonomyConnectionResolver.php │ │ ├── TermObjectConnectionResolver.php │ │ ├── ThemeConnectionResolver.php │ │ ├── UserConnectionResolver.php │ │ └── UserRoleConnectionResolver.php │ ├── Cursor │ │ ├── AbstractCursor.php │ │ ├── CommentObjectCursor.php │ │ ├── CursorBuilder.php │ │ ├── PostObjectCursor.php │ │ ├── TermObjectCursor.php │ │ └── UserCursor.php │ ├── DataSource.php │ ├── Loader │ │ ├── AbstractDataLoader.php │ │ ├── CommentAuthorLoader.php │ │ ├── CommentLoader.php │ │ ├── EnqueuedScriptLoader.php │ │ ├── EnqueuedStylesheetLoader.php │ │ ├── PluginLoader.php │ │ ├── PostObjectLoader.php │ │ ├── PostTypeLoader.php │ │ ├── README.md │ │ ├── TaxonomyLoader.php │ │ ├── TermObjectLoader.php │ │ ├── ThemeLoader.php │ │ ├── UserLoader.php │ │ └── UserRoleLoader.php │ ├── MediaItemMutation.php │ ├── NodeResolver.php │ ├── PostObjectMutation.php │ ├── README.md │ ├── TermObjectMutation.php │ └── UserMutation.php ├── Model │ ├── Avatar.php │ ├── Comment.php │ ├── CommentAuthor.php │ ├── Menu.php │ ├── MenuItem.php │ ├── Model.php │ ├── Plugin.php │ ├── Post.php │ ├── PostType.php │ ├── Taxonomy.php │ ├── Term.php │ ├── Theme.php │ ├── User.php │ └── UserRole.php ├── Mutation │ ├── CommentCreate.php │ ├── CommentDelete.php │ ├── CommentRestore.php │ ├── CommentUpdate.php │ ├── MediaItemCreate.php │ ├── MediaItemDelete.php │ ├── MediaItemUpdate.php │ ├── PostObjectCreate.php │ ├── PostObjectDelete.php │ ├── PostObjectUpdate.php │ ├── README.md │ ├── ResetUserPassword.php │ ├── SendPasswordResetEmail.php │ ├── TermObjectCreate.php │ ├── TermObjectDelete.php │ ├── TermObjectUpdate.php │ ├── UpdateSettings.php │ ├── UserCreate.php │ ├── UserDelete.php │ ├── UserRegister.php │ └── UserUpdate.php ├── Registry │ ├── SchemaRegistry.php │ ├── TypeRegistry.php │ └── Utils │ │ ├── PostObject.php │ │ └── TermObject.php ├── Request.php ├── Router.php ├── Server │ ├── ValidationRules │ │ ├── DisableIntrospection.php │ │ ├── QueryDepth.php │ │ └── RequireAuthentication.php │ └── WPHelper.php ├── Type │ ├── Connection │ │ ├── Comments.php │ │ ├── MenuItems.php │ │ ├── PostObjects.php │ │ ├── README.md │ │ ├── Taxonomies.php │ │ ├── TermObjects.php │ │ └── Users.php │ ├── Enum │ │ ├── AvatarRatingEnum.php │ │ ├── CommentNodeIdTypeEnum.php │ │ ├── CommentStatusEnum.php │ │ ├── CommentsConnectionOrderbyEnum.php │ │ ├── ContentNodeIdTypeEnum.php │ │ ├── ContentTypeEnum.php │ │ ├── ContentTypeIdTypeEnum.php │ │ ├── MediaItemSizeEnum.php │ │ ├── MediaItemStatusEnum.php │ │ ├── MenuItemNodeIdTypeEnum.php │ │ ├── MenuLocationEnum.php │ │ ├── MenuNodeIdTypeEnum.php │ │ ├── MimeTypeEnum.php │ │ ├── OrderEnum.php │ │ ├── PluginStatusEnum.php │ │ ├── PostObjectFieldFormatEnum.php │ │ ├── PostObjectsConnectionDateColumnEnum.php │ │ ├── PostObjectsConnectionOrderbyEnum.php │ │ ├── PostStatusEnum.php │ │ ├── RelationEnum.php │ │ ├── ScriptLoadingGroupLocationEnum.php │ │ ├── ScriptLoadingStrategyEnum.php │ │ ├── TaxonomyEnum.php │ │ ├── TaxonomyIdTypeEnum.php │ │ ├── TermNodeIdTypeEnum.php │ │ ├── TermObjectsConnectionOrderbyEnum.php │ │ ├── TimezoneEnum.php │ │ ├── UserNodeIdTypeEnum.php │ │ ├── UserRoleEnum.php │ │ ├── UsersConnectionOrderbyEnum.php │ │ └── UsersConnectionSearchColumnEnum.php │ ├── Input │ │ ├── DateInput.php │ │ ├── DateQueryInput.php │ │ ├── PostObjectsConnectionOrderbyInput.php │ │ └── UsersConnectionOrderbyInput.php │ ├── InterfaceType │ │ ├── Commenter.php │ │ ├── Connection.php │ │ ├── ContentNode.php │ │ ├── ContentTemplate.php │ │ ├── DatabaseIdentifier.php │ │ ├── Edge.php │ │ ├── EnqueuedAsset.php │ │ ├── HierarchicalContentNode.php │ │ ├── HierarchicalNode.php │ │ ├── HierarchicalTermNode.php │ │ ├── MenuItemLinkable.php │ │ ├── Node.php │ │ ├── NodeWithAuthor.php │ │ ├── NodeWithComments.php │ │ ├── NodeWithContentEditor.php │ │ ├── NodeWithExcerpt.php │ │ ├── NodeWithFeaturedImage.php │ │ ├── NodeWithPageAttributes.php │ │ ├── NodeWithRevisions.php │ │ ├── NodeWithTemplate.php │ │ ├── NodeWithTitle.php │ │ ├── NodeWithTrackbacks.php │ │ ├── OneToOneConnection.php │ │ ├── PageInfo.php │ │ ├── Previewable.php │ │ ├── TermNode.php │ │ └── UniformResourceIdentifiable.php │ ├── ObjectType │ │ ├── Avatar.php │ │ ├── Comment.php │ │ ├── CommentAuthor.php │ │ ├── ContentType.php │ │ ├── EnqueuedScript.php │ │ ├── EnqueuedStylesheet.php │ │ ├── MediaDetails.php │ │ ├── MediaItemMeta.php │ │ ├── MediaSize.php │ │ ├── Menu.php │ │ ├── MenuItem.php │ │ ├── Plugin.php │ │ ├── PostObject.php │ │ ├── PostTypeLabelDetails.php │ │ ├── RootMutation.php │ │ ├── RootQuery.php │ │ ├── SettingGroup.php │ │ ├── Settings.php │ │ ├── Taxonomy.php │ │ ├── TermObject.php │ │ ├── Theme.php │ │ ├── User.php │ │ └── UserRole.php │ ├── README.md │ ├── Union │ │ ├── MenuItemObjectUnion.php │ │ ├── PostObjectUnion.php │ │ └── TermObjectUnion.php │ ├── WPConnectionType.php │ ├── WPEnumType.php │ ├── WPInputObjectType.php │ ├── WPInterfaceTrait.php │ ├── WPInterfaceType.php │ ├── WPMutationType.php │ ├── WPObjectType.php │ ├── WPScalar.php │ └── WPUnionType.php ├── Types.php ├── Utils │ ├── DebugLog.php │ ├── InstrumentSchema.php │ ├── Preview.php │ ├── QueryAnalyzer.php │ ├── QueryLog.php │ ├── Tracing.php │ └── Utils.php ├── WPGraphQL.php ├── WPSchema.php └── assets │ ├── README.md │ └── wpgraphql-elephant.svg ├── tests ├── .gitignore ├── _data │ ├── .gitignore │ ├── classes │ │ ├── WP_Query_Custom.php │ │ └── WP_Query_Incompatible.php │ ├── config.php │ ├── images │ │ ├── .gitignore │ │ ├── test-2000x1000.png │ │ ├── test-medium.png │ │ ├── test-mgc.gif │ │ └── test.png │ ├── media │ │ └── test.pdf │ ├── plugins │ │ ├── plugin-incompatible-version.php │ │ ├── plugin-with-headers.php │ │ ├── plugin-with-meta.php │ │ └── plugin-with-requires.php │ └── templates │ │ ├── custom-i18n.php │ │ ├── custom.php │ │ └── תבנית-שלי.php ├── _envs │ └── docker.yml ├── _output │ └── .gitignore ├── _support │ ├── AcceptanceTester.php │ ├── FunctionalTester.php │ ├── Helper │ │ ├── Acceptance.php │ │ ├── Functional.php │ │ ├── Unit.php │ │ └── Wpunit.php │ ├── UnitTester.php │ ├── WpunitTester.php │ └── _generated │ │ └── .gitignore ├── acceptance.suite.dist.yml ├── acceptance │ ├── PluginActivatedCest.php │ └── TwoDomainsSupportedCest.php ├── e2e │ ├── config │ │ └── global-setup.js │ ├── playwright.config.js │ ├── plugins │ │ ├── README.md │ │ └── settings-page-spec │ │ │ └── settings-page-spec.php │ ├── specs │ │ ├── graphiql.spec.js │ │ └── settings-page.spec.js │ └── utils.js ├── functional.suite.dist.yml ├── functional │ ├── ApolloPreflightRequestCept.php │ ├── BasicPostListCept.php │ ├── BatchQueriesCept.php │ ├── BatchQueriesDisabledCept.php │ ├── CommentConnectionQueriesCept.php │ ├── ContentTypeHeaderCept.php │ ├── GraphQLHeadersCept.php │ ├── GraphqlSettingsPageCept.php │ ├── MenuWithMenuItemsCept.php │ ├── PostListWithDifferentStatusCept.php │ ├── QueryDepthRuleCept.php │ ├── RestrictedQueriesCept.php │ └── bootstrap.php ├── wpunit.suite.dist.yml └── wpunit │ ├── AccessFunctionsTest.php │ ├── AdminNoticesTest.php │ ├── AssertValidSchemaTest.php │ ├── AvatarObjectQueriesTest.php │ ├── CommentConnectionQueriesTest.php │ ├── CommentMutationsTest.php │ ├── CommentObjectCursorTest.php │ ├── CommentObjectQueriesTest.php │ ├── ConnectionInterfaceTest.php │ ├── ConnectionRegistrationTest.php │ ├── ContentNodeInterfaceTest.php │ ├── ContentTemplateTest.php │ ├── ContentTypeConnectionQueriesTest.php │ ├── CustomPostTypeTest.php │ ├── CustomTaxonomyTest.php │ ├── DataConfigTest.php │ ├── DebugLogTest.php │ ├── EnqueuedScriptsTest.php │ ├── EnqueuedStylesheetsTest.php │ ├── FiltersTest.php │ ├── InterfaceTest.php │ ├── IsGraphqlHttpRequestTest.php │ ├── MediaItemMutationsTest.php │ ├── MediaItemQueriesTest.php │ ├── MenuConnectionQueriesTest.php │ ├── MenuItemConnectionQueriesTest.php │ ├── MenuItemConnectionResolverTest.php │ ├── MenuItemQueriesTest.php │ ├── MenuQueriesTest.php │ ├── ModelUserTest.php │ ├── NodeBySlugTest.php │ ├── NodeByUriTest.php │ ├── NodesTest.php │ ├── PageByUriTest.php │ ├── PluginCompatibilityTest.php │ ├── PluginConnectionQueriesTest.php │ ├── PluginObjectQueriesTest.php │ ├── PostConnectionPaginationTest.php │ ├── PostObjectConnectionQueriesTest.php │ ├── PostObjectCursorTest.php │ ├── PostObjectMutationsTest.php │ ├── PostObjectNestedMutationsTest.php │ ├── PostObjectQueriesTest.php │ ├── PostTypeObjectQueriesTest.php │ ├── PreresolveTest.php │ ├── PreviewContentNodesTest.php │ ├── PreviewTest.php │ ├── QueryAnalyzerTest.php │ ├── README.md │ ├── RegisterInterfaceToTypeTest.php │ ├── RegisteredScriptConnectionQueriesTest.php │ ├── RegisteredStylesheetConnectionQueriesTest.php │ ├── RequestTest.php │ ├── RevisionTest.php │ ├── RootQueryConnectionsTest.php │ ├── RouterTest.php │ ├── SemVerTest.php │ ├── SettingQueriesTest.php │ ├── SettingsMutationsTest.php │ ├── SettingsQueriesTest.php │ ├── ShouldShowAdminToolbarQueryTest.php │ ├── TaxonomyConnectionQueriesTest.php │ ├── TaxonomyObjectQueriesTest.php │ ├── TermNodeTest.php │ ├── TermObjectConnectionQueriesTest.php │ ├── TermObjectCursorTest.php │ ├── TermObjectMutationsTest.php │ ├── TermObjectQueriesTest.php │ ├── ThemeConnectionQueriesTest.php │ ├── ThemeObjectQueriesTest.php │ ├── TracingTest.php │ ├── TypesTest.php │ ├── UpdatesTest.php │ ├── UserConnectionPaginationTest.php │ ├── UserConnectionQueriesTest.php │ ├── UserObjectCursorTest.php │ ├── UserObjectMutationsTest.php │ ├── UserObjectQueriesTest.php │ ├── UserRoleConnectionQueriesTest.php │ ├── UserRoleEnumTest.php │ ├── UserRoleObjectQueriesTest.php │ ├── UtilsTest.php │ ├── ViewerQueryTest.php │ ├── WPEnumTypeTest.php │ ├── WPGraphQLAccessFunctionsTest.php │ ├── WPGraphQLTest.php │ └── WPHelperTest.php ├── webpack.config.js └── wp-graphql.php /.changesets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/.changesets/.gitkeep -------------------------------------------------------------------------------- /.changesets/archive/2025-06-18-pr-3371.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "fix: make void and call on " 3 | pr: 3371 4 | author: "justlevine" 5 | type: "fix" 6 | breaking: false 7 | --- 8 | 9 | ## What does this implement/fix? Explain your changes. 10 | 11 | This PR fixes a code quality bug where the \`do_graphql_request\` was incorrectly being called via \`add_filter()\` instead of \`add_action()\`. 12 | 13 | As a result of this change, the \`Tracing::init_trace()\` has been changed from returning a \`float\` unused by the application to returning \`void\`. 14 | 15 | This is _technically_ a breaking change, as that method is public, and the Tracing class is not marked \`final\`. However, there doesn't seem to be a way _in_ WPGraphQL to replace this version with an extended version (unlike some other filterable classes). 16 | 17 | > [!IMPORTANT] 18 | > ~This PR is based on #3368 which should be merged first.~ 19 | > 20 | > ~Relevant diff for this PR is: https://github.com/wp-graphql/wp-graphql/commit/3f0de2398b75dcf63f7ff98ea0c677f3fa5d54a9~ 21 | > Rebased ✔️ 22 | 23 | ## Does this close any currently open issues? 24 | 25 | 26 | 27 | Not directly, but if we consider this a breaking change than it's part of #3370 . Converting the entire class to \`final\` would be part of that ticket for sure. 28 | 29 | ## Any other comments? 30 | -------------------------------------------------------------------------------- /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | checks: 3 | method-lines: 4 | config: 5 | threshold: 40 6 | -------------------------------------------------------------------------------- /.cursor/rules/README.md: -------------------------------------------------------------------------------- 1 | # WPGraphQL Cursor Rules 2 | 3 | This directory contains project-specific rules for Cursor, an AI-powered code editor. These rules help the AI understand the structure and patterns of the WPGraphQL codebase. 4 | 5 | ## Rule Files 6 | 7 | - **wpgraphql.json**: The main rule file that contains information about the WPGraphQL project, including frameworks, key concepts, file patterns, dependencies, and more. 8 | 9 | ## How These Rules Help 10 | 11 | These rules provide context to the AI when working with the WPGraphQL codebase, enabling it to: 12 | 13 | 1. Understand the project structure and architecture 14 | 2. Recognize common code patterns 15 | 3. Identify key files and directories 16 | 4. Understand the purpose of different components 17 | 5. Provide more accurate and relevant suggestions 18 | 19 | ## For Contributors 20 | 21 | If you're contributing to WPGraphQL and using Cursor, these rules will automatically be applied when you open the project in Cursor. This ensures that all contributors have the same context when working with the codebase. 22 | 23 | ## Updating Rules 24 | 25 | If you need to update these rules, please modify the appropriate JSON file in this directory. Make sure to follow the existing structure and format. 26 | 27 | ## Learn More 28 | 29 | For more information about Cursor rules, visit the [Cursor documentation](https://docs.cursor.com/context/rules-for-ai). 30 | -------------------------------------------------------------------------------- /.cursor/rules/wpgraphql.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: 3 | globs: 4 | --- 5 | 6 | # Your rule content 7 | 8 | - You can @ files here 9 | - You can use markdown but dont have to 10 | -------------------------------------------------------------------------------- /.distignore: -------------------------------------------------------------------------------- 1 | /.git 2 | /.github 3 | /.idea 4 | /.log 5 | /.vscode 6 | /.wordpress-org 7 | /bin 8 | /github 9 | /plugin-build 10 | /documentation 11 | /docs 12 | /img 13 | /phpstan 14 | /tests 15 | /docker 16 | /docker-output 17 | /tests 18 | /node_modules 19 | /packages 20 | /artifacts 21 | /.changeset 22 | /scripts 23 | .cursor 24 | .changesets 25 | .husky 26 | .nvmrc 27 | .babel.config.cjs 28 | jest.config.js 29 | .DS_Store 30 | .distignore 31 | .dockerignore 32 | .env 33 | .env.dist 34 | .gitattributes 35 | .gitignore 36 | .github_changelog_generator 37 | c3.php 38 | CHANGELOG.md 39 | codeception.dist.yml 40 | codeception.yml 41 | composer.json 42 | composer.lock 43 | docker-compose.yml 44 | netlify.toml 45 | package-lock.json 46 | package.json 47 | phpcs.xml 48 | phpstan.neon.dist 49 | phpunit.xml.dist 50 | README.md 51 | schema.graphql 52 | webpack.config.js 53 | phpcs.xml.dist 54 | .wp-env.json 55 | .codeclimate.yml 56 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | # The following files should be ignored: 2 | # - unencrypted sensitive data 3 | # - files that are not checked into the code repository 4 | # - files that are not relevant to the Docker build 5 | 6 | .git 7 | .idea 8 | bin 9 | docker-output 10 | docs 11 | img 12 | 13 | tests/_output 14 | !tests/_output/.gitignore 15 | tests/_support/_generated 16 | !tests/_support/_generated/.gitignore 17 | 18 | vendor 19 | !vendor/autoload.php 20 | !vendor/ivome/graphql-relay-php/src 21 | !vendor/webonyx/graphql-php/src 22 | !vendor/composer 23 | 24 | .dockerignore 25 | .gitignore 26 | .travis.yml 27 | CODE_OF_CONDUCT.md 28 | CONTRIBUTING.md 29 | Dockerfile* 30 | ISSUE_TEMPLATE.md 31 | LICENSE 32 | PULL_REQUEST_TEMPLATE.md 33 | README.md 34 | readme.txt 35 | run-docker*.sh 36 | -------------------------------------------------------------------------------- /.env.dist: -------------------------------------------------------------------------------- 1 | DB_NAME=wordpress 2 | DB_HOST=app_db 3 | DB_USER=wordpress 4 | DB_PASSWORD=wordpress 5 | WP_TABLE_PREFIX=wp_ 6 | WP_URL=http://localhost 7 | WP_DOMAIN=localhost 8 | ADMIN_EMAIL=admin@example.com 9 | ADMIN_USERNAME=admin 10 | ADMIN_PASSWORD=password 11 | ADMIN_PATH=/wp-admin 12 | 13 | TEST_DB_NAME=wptests 14 | TEST_DB_HOST=127.0.0.1 15 | TEST_DB_USER=root 16 | TEST_DB_PASSWORD=root 17 | TEST_WP_TABLE_PREFIX=wp_ 18 | 19 | SKIP_DB_CREATE=false 20 | TEST_WP_ROOT_FOLDER=/tmp/wordpress 21 | TEST_ADMIN_EMAIL=admin@wp.test 22 | 23 | TESTS_DIR=tests 24 | TESTS_OUTPUT=tests/_output 25 | TESTS_DATA=tests/_data 26 | TESTS_SUPPORT=tests/_support 27 | TESTS_ENVS=tests/_envs 28 | 29 | CORE_BRANCH=develop 30 | SKIP_TESTS_CLEANUP=1 31 | SUITES=wpunit 32 | 33 | WORDPRESS_DB_HOST=${DB_HOST} 34 | WORDPRESS_DB_USER=${DB_USER} 35 | WORDPRESS_DB_PASSWORD=${DB_PASSWORD} 36 | WORDPRESS_DB_NAME=${DB_NAME} 37 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Remember, an issue is not the place to ask general questions. You can use [Slack](https://wp-graphql.slack.com) for that ([join here](https://join.slack.com/t/wp-graphql/shared_invite/zt-3vloo60z-PpJV2PFIwEathWDOxCTTLA)). 2 | 3 | Before you open an issue, please check if a similar issue already exists or has been closed before. 4 | 5 | ### When reporting a _bug_, please be sure to include the following: 6 | - [ ] A descriptive title 7 | - [ ] An *isolated* way to reproduce the behavior (example: GitHub repository with code isolated to the issue that anyone can clone to observe the problem) 8 | - [ ] What version of `WPGraphQL` you're using, and the platform(s) you're running it on 9 | - [ ] What other plugins you're using 10 | - [ ] The behavior you expect to see, and the actual behavior 11 | 12 | ### When you open an _issue_ for a feature request, please add as much detail as possible: 13 | - [ ] A descriptive title 14 | - [ ] A description of the problem you're trying to solve, including *why* you think this is a problem 15 | - [ ] An overview of the suggested solution 16 | - [ ] If the feature changes current behavior, reasons why your solution is better 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: General Help Request 4 | url: https://github.com/wp-graphql/wp-graphql/discussions 5 | about: For general questions and help requests, create a new topic in Github Discussions 6 | - name: Discord Community 7 | url: https://www.wpgraphql.com/discord 8 | about: The WPGraphQL Discord is a great place to communicate in real-time. Ask questions, discuss features, get to know other folks using WPGraphQL. 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature request 2 | description: Suggest an idea, feature, or enhancement for WPGraphQL. 3 | body: 4 | - type: markdown 5 | attributes: 6 | value: >- 7 | Thank you for taking the time to submit a feature request. 8 | 9 | 10 | Please make sure to search the repo for [existing feature 11 | requests](https://github.com/wp-graphql/wp-graphql/issues) 12 | before creating a new one. 13 | - type: textarea 14 | attributes: 15 | label: What problem does this address? 16 | description: >- 17 | Please describe the problem you are trying to solve, including why you 18 | think this is a problem. 19 | placeholder: I'm always frustrated when [...] 20 | validations: 21 | required: true 22 | - type: textarea 23 | attributes: 24 | label: What is your proposed solution? 25 | description: >- 26 | Please provide a clear and concise description of your suggested 27 | solution. 28 | placeholder: What I'd like to see happen is [...] 29 | validations: 30 | required: true 31 | - type: textarea 32 | attributes: 33 | label: What alternatives have you considered? 34 | description: >- 35 | Please list any alternatives you have considered, and why you think your 36 | solution is better. 37 | - type: textarea 38 | attributes: 39 | label: Additional Context 40 | description: Add any other context or screenshots about the feature request here. 41 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | <!-- 2 | 3 | ### Your checklist for this pull request 4 | Thanks for sending a pull request! Please make sure you click the link above to view the contribution guidelines, then fill out the blanks below. 5 | 6 | 🚨 Please review the guidelines for contributing to this repository: https://github.com/wp-graphql/wp-graphql/blob/develop/.github/CONTRIBUTING.md 7 | 8 | - [ ] Make sure your PR title follows Conventional Commit standards. See: https://www.conventionalcommits.org/en/v1.0.0/#specification . Allowed prefixes: `build`, `chore`, `ci`, `docs`, `feat`, `fix`, `perf`, `refactor`, `revert`, `style`, `test` 9 | - [ ] Make sure you are making a pull request against the **develop branch** (left side). Also you should start *your branch* off *our master*. 10 | - [ ] Make sure you are requesting to pull request from a **topic/feature/bugfix branch** (right side). Don't pull request from your master! 11 | 12 | --> 13 | 14 | ## What does this implement/fix? Explain your changes. 15 | 16 | 17 | ## Does this close any currently open issues? 18 | 19 | <!-- 20 | ### Write "closes #{pr number}" 21 | ### see: https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword 22 | --> 23 | 24 | ## Any other comments? 25 | 26 | <!-- Please add any additional context that would be helpful. Feel free to include screenshots of the GraphiQL IDE or other relevant screenshotes, logs, error output, etc --> 27 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 90 3 | # Stalebot will close issues marked "stale?" if they have not been triaged after 90 days. 4 | # See https://github.com/wp-graphql/wp-graphql/issues/2494 5 | daysUntilClose: false 6 | # Issues with these labels will never be considered stale 7 | exemptLabels: 8 | - "not stale" 9 | - "🚨 Importance: Critical" 10 | - "Ready for Review" 11 | - "Release" 12 | - "Target: v2.0" 13 | - "status: blocked" 14 | # Stalebot will mark issues as stale? after 90 days 15 | # If stale? issues haven't been triaged after another 90 days, they will be closed. 16 | # See: https://github.com/wp-graphql/wp-graphql/issues/2494 17 | staleLabel: "stale?" 18 | # Comment to post when marking an issue as stale. Set to `false` to disable 19 | markComment: > 20 | This issue has been automatically marked as stale because it has not had 21 | recent activity. You can help keep it active by commenting with additional information or even just confirming the issue still exists. We thank you for your contributions. 22 | -------------------------------------------------------------------------------- /.github/workflows/code-quality.yml: -------------------------------------------------------------------------------- 1 | name: Code Quality 2 | 3 | on: 4 | push: 5 | branches: 6 | - develop 7 | - master 8 | - release/* 9 | pull_request: 10 | branches: 11 | - develop 12 | - master 13 | - release/* 14 | 15 | # Cancel previous workflow run groups that have not completed. 16 | concurrency: 17 | # Group workflow runs by workflow name, along with the head branch ref of the pull request 18 | # or otherwise the branch or tag ref. 19 | group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.ref }} 20 | cancel-in-progress: true 21 | 22 | jobs: 23 | run: 24 | runs-on: ubuntu-latest 25 | name: Check code 26 | 27 | steps: 28 | - name: Checkout 29 | uses: actions/checkout@v4 30 | 31 | - name: Setup PHP 32 | uses: shivammathur/setup-php@v2 33 | with: 34 | php-version: 8.2 35 | tools: composer:v2 36 | coverage: none 37 | 38 | - name: Install dependencies 39 | uses: ramsey/composer-install@v3 40 | with: 41 | composer-options: "--no-progress" 42 | 43 | - name: Run PHPStan 44 | # If STEP_DEBUG is enabled, PHPStan will run in debug mode. 45 | run: | 46 | if [ "${{ secrets.ACTIONS_STEP_DEBUG }}" = "true" ]; then 47 | php vendor/bin/phpstan analyse --memory-limit=2G --debug 48 | else 49 | composer run-script phpstan 50 | fi 51 | -------------------------------------------------------------------------------- /.github/workflows/lint-pr.yml: -------------------------------------------------------------------------------- 1 | name: "Lint Pull Request" 2 | 3 | on: 4 | pull_request_target: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | 10 | jobs: 11 | main: 12 | name: Validate Pull Request Title 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: amannn/action-semantic-pull-request@v5 16 | env: 17 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 18 | with: 19 | # see: https://github.com/commitizen/conventional-commit-types 20 | types: | 21 | build 22 | chore 23 | ci 24 | docs 25 | feat 26 | fix 27 | perf 28 | refactor 29 | release 30 | revert 31 | style 32 | test 33 | requireScope: false 34 | ignoreLabels: | 35 | bot 36 | ignore-semantic-pull-request 37 | # For work-in-progress PRs you can typically use draft pull requests 38 | # from GitHub. However, private repositories on the free plan don't have 39 | # this option and therefore this action allows you to opt-in to using the 40 | # special "[WIP]" prefix to indicate this state. This will avoid the 41 | # validation of the PR title and the pull request checks remain pending. 42 | # Note that a second check will be reported if this is enabled. 43 | wip: true 44 | -------------------------------------------------------------------------------- /.github/workflows/upload-schema-artifact.yml: -------------------------------------------------------------------------------- 1 | name: Upload Schema Artifact 2 | 3 | on: 4 | release: 5 | types: [ published ] 6 | 7 | jobs: 8 | run: 9 | runs-on: ubuntu-latest 10 | name: Generate and Upload WPGraphQL Schema Artifact 11 | services: 12 | mariadb: 13 | image: mariadb:10 14 | ports: 15 | - 3306:3306 16 | env: 17 | MYSQL_ROOT_PASSWORD: root 18 | # Ensure docker waits for mariadb to start 19 | options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 20 | 21 | steps: 22 | - name: Checkout 23 | uses: actions/checkout@v4 24 | 25 | - name: Setup PHP w/ Composer & WP-CLI 26 | uses: shivammathur/setup-php@v2 27 | with: 28 | php-version: 8.2 29 | extensions: mbstring, intl, bcmath, exif, gd, mysqli, opcache, zip, pdo_mysql 30 | coverage: none 31 | tools: composer, wp-cli 32 | 33 | - name: Setup WordPress 34 | run: | 35 | composer run install-test-env 36 | 37 | - name: Generate the Static Schema 38 | run: | 39 | cd /tmp/wordpress/ 40 | # Output: /tmp/schema.graphql 41 | wp graphql generate-static-schema 42 | 43 | - name: Upload schema as release artifact 44 | uses: softprops/action-gh-release@v2 45 | with: 46 | files: /tmp/schema.graphql 47 | env: 48 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 49 | -------------------------------------------------------------------------------- /.github/workflows/wordpress-coding-standards.yml: -------------------------------------------------------------------------------- 1 | name: WordPress Coding Standards 2 | 3 | on: 4 | push: 5 | branches: 6 | - develop 7 | - master 8 | - release/* 9 | pull_request: 10 | branches: 11 | - develop 12 | - master 13 | - release/* 14 | 15 | # Cancel previous workflow run groups that have not completed. 16 | concurrency: 17 | # Group workflow runs by workflow name, along with the head branch ref of the pull request 18 | # or otherwise the branch or tag ref. 19 | group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.ref }} 20 | cancel-in-progress: true 21 | 22 | jobs: 23 | run: 24 | runs-on: ubuntu-latest 25 | name: PHPCS 26 | 27 | steps: 28 | - name: Checkout 29 | uses: actions/checkout@v4 30 | 31 | - name: Setup PHP 32 | uses: shivammathur/setup-php@v2 33 | with: 34 | php-version: 8.2 35 | tools: composer:v2 36 | coverage: none 37 | 38 | - name: Install dependencies 39 | uses: ramsey/composer-install@v3 40 | with: 41 | composer-options: "--no-progress" 42 | 43 | - name: Run PHPCS 44 | run: composer run-script check-cs 45 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 20 2 | -------------------------------------------------------------------------------- /.wordpress-org/banner-1544x500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/.wordpress-org/banner-1544x500.png -------------------------------------------------------------------------------- /.wordpress-org/banner-772x250.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/.wordpress-org/banner-772x250.png -------------------------------------------------------------------------------- /.wordpress-org/blueprints/blueprint.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://playground.wordpress.net/blueprint-schema.json", 3 | "meta": { 4 | "title": "Use WPGraphQL to query WordPress", 5 | "description": "Example that loads WordPress with WPGraphQL active and defaults to the WPGraphQL IDE page to allow users to test GraphQL queries and explore the GraphQL Schema.", 6 | "author": "jasonbahl", 7 | "categories": ["API", "wpgraphql"] 8 | }, 9 | "landingPage": "/wp-admin/admin.php?page=graphiql-ide&query=I4VwpgTgngBA4mALgBQPYGdHpgbwFAwwAOGWuBhMAdqgCZjb6WUCWtFziLiANmB5VoBDRP2YBfCpPFA", 10 | "plugins": [ 11 | "wp-graphql" 12 | ], 13 | "steps": [ 14 | { 15 | "step": "login", 16 | "username": "admin" 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /.wordpress-org/icon-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/.wordpress-org/icon-128x128.png -------------------------------------------------------------------------------- /.wordpress-org/icon-256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/.wordpress-org/icon-256x256.png -------------------------------------------------------------------------------- /.wordpress-org/screenshot-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/.wordpress-org/screenshot-1.jpg -------------------------------------------------------------------------------- /.wordpress-org/screenshot-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/.wordpress-org/screenshot-2.jpg -------------------------------------------------------------------------------- /.wp-env.json: -------------------------------------------------------------------------------- 1 | { 2 | "core": "WordPress/WordPress", 3 | "plugins": [ 4 | "./tests/e2e/plugins/settings-page-spec/", 5 | "." 6 | ], 7 | "themes": [], 8 | "port": 8888, 9 | "config": { 10 | "WP_DEBUG": true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /activation.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Runs when WPGraphQL is activated 4 | */ 5 | function graphql_activation_callback(): void { 6 | do_action( 'graphql_activate' ); 7 | } 8 | -------------------------------------------------------------------------------- /build/app.asset.php: -------------------------------------------------------------------------------- 1 | <?php return array('dependencies' => array('react', 'react-dom', 'wp-element', 'wp-hooks'), 'version' => '3602bbf51bf72c1cf8e4'); 2 | -------------------------------------------------------------------------------- /build/extensions-rtl.css: -------------------------------------------------------------------------------- 1 | .plugin-card .desc,.plugin-card .desc>p,.plugin-card .name{margin-right:0}.plugin-card .name{margin-bottom:10px}.plugin-card-top{min-height:110px}.plugin-card-top h2{margin:0}@media screen and (max-width:782px){.plugin-card-top{min-height:110px}}.plugin-card .perflab-plugin-experimental{font-size:80%;font-weight:400}@media (max-width:480px),screen and (max-width:1100px)and (min-width:782px){.plugin-card .action-links{margin-right:auto}.plugin-card .plugin-action-buttons>li:nth-child(3){border-right:1px solid;margin-right:2ex;padding-right:2ex}} 2 | -------------------------------------------------------------------------------- /build/extensions.asset.php: -------------------------------------------------------------------------------- 1 | <?php return array('dependencies' => array('react', 'wp-api-fetch', 'wp-components', 'wp-element', 'wp-i18n'), 'version' => '72bcf21912629c604280'); 2 | -------------------------------------------------------------------------------- /build/extensions.css: -------------------------------------------------------------------------------- 1 | .plugin-card .desc,.plugin-card .desc>p,.plugin-card .name{margin-left:0}.plugin-card .name{margin-bottom:10px}.plugin-card-top{min-height:110px}.plugin-card-top h2{margin:0}@media screen and (max-width:782px){.plugin-card-top{min-height:110px}}.plugin-card .perflab-plugin-experimental{font-size:80%;font-weight:400}@media (max-width:480px),screen and (max-width:1100px)and (min-width:782px){.plugin-card .action-links{margin-left:auto}.plugin-card .plugin-action-buttons>li:nth-child(3){border-left:1px solid;margin-left:2ex;padding-left:2ex}} 2 | -------------------------------------------------------------------------------- /build/graphiqlAuthSwitch.asset.php: -------------------------------------------------------------------------------- 1 | <?php return array('dependencies' => array('react', 'react-dom', 'wp-element'), 'version' => '1987803dd89818cb06fe'); 2 | -------------------------------------------------------------------------------- /build/graphiqlFullscreenToggle-rtl.css: -------------------------------------------------------------------------------- 1 | .graphiql-fullscreen #wp-graphiql-wrapper{inset:0;padding:0;position:fixed;z-index:99999}#graphiql-fullscreen-toggle{align-items:center;display:flex;height:30px;justify-content:center;padding:8px}#wp-graphiql-wrapper .contract-icon,.graphiql-fullscreen #wp-graphiql-wrapper .expand-icon{display:none}.graphiql-fullscreen #wp-graphiql-wrapper .contract-icon{display:block} 2 | -------------------------------------------------------------------------------- /build/graphiqlFullscreenToggle.asset.php: -------------------------------------------------------------------------------- 1 | <?php return array('dependencies' => array('react'), 'version' => '0f61bf40b34560ea7c28'); 2 | -------------------------------------------------------------------------------- /build/graphiqlFullscreenToggle.css: -------------------------------------------------------------------------------- 1 | .graphiql-fullscreen #wp-graphiql-wrapper{inset:0;padding:0;position:fixed;z-index:99999}#graphiql-fullscreen-toggle{align-items:center;display:flex;height:30px;justify-content:center;padding:8px}#wp-graphiql-wrapper .contract-icon,.graphiql-fullscreen #wp-graphiql-wrapper .expand-icon{display:none}.graphiql-fullscreen #wp-graphiql-wrapper .contract-icon{display:block} 2 | -------------------------------------------------------------------------------- /build/graphiqlFullscreenToggle.js: -------------------------------------------------------------------------------- 1 | (()=>{"use strict";const e=window.React,{hooks:t}=window.wpGraphiQL,o=()=>(0,e.createElement)("button",{id:"graphiql-fullscreen-toggle",className:"toolbar-button",title:"Toggle Full Screen",onClick:()=>{document.body.classList.toggle("graphiql-fullscreen")}},(0,e.createElement)("svg",{xmlns:"http://www.w3.org/2000/svg",width:"18",height:"18",className:"expand-icon",viewBox:"0 0 512 512"},(0,e.createElement)("path",{fill:"none",stroke:"currentColor",strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:"32",d:"M432 320v112H320M421.8 421.77L304 304M80 192V80h112M90.2 90.23L208 208M320 80h112v112M421.77 90.2L304 208M192 432H80V320M90.23 421.8L208 304"})),(0,e.createElement)("svg",{xmlns:"http://www.w3.org/2000/svg",width:"18",height:"18",className:"contract-icon",viewBox:"0 0 512 512"},(0,e.createElement)("path",{fill:"none",stroke:"currentColor",strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:"32",d:"M304 416V304h112M314.2 314.23L432 432M208 96v112H96M197.8 197.77L80 80M416 208H304V96M314.23 197.8L432 80M96 304h112v112M197.77 314.2L80 432"})));t.addFilter("graphiql_toolbar_after_buttons","graphiql-extension",((t,n)=>(t.push((0,e.createElement)(o,{key:"fullscreen-toggle"})),t)))})(); -------------------------------------------------------------------------------- /build/graphiqlQueryComposer-rtl.css: -------------------------------------------------------------------------------- 1 | #wp-graphiql-wrapper .docExplorerWrap{background:#fff;box-shadow:0 0 8px rgba(0,0,0,.15);position:relative;z-index:4}#wp-graphiql-wrapper .docExplorerWrap .doc-explorer-title-bar{cursor:default;display:flex;height:34px;line-height:14px;padding:8px 8px 5px;position:relative;-webkit-user-select:none;-moz-user-select:none;user-select:none}#wp-graphiql-wrapper .docExplorerWrap .doc-explorer-title{flex:1 1;font-weight:700;overflow-x:hidden;overflow-y:hidden;padding:5px 10px 10px 0;text-align:center;text-overflow:ellipsis;-webkit-user-select:text;-moz-user-select:text;user-select:text;white-space:nowrap}#wp-graphiql-wrapper .docExplorerWrap .doc-explorer-rhs{position:relative} 2 | -------------------------------------------------------------------------------- /build/graphiqlQueryComposer.asset.php: -------------------------------------------------------------------------------- 1 | <?php return array('dependencies' => array('react', 'react-dom'), 'version' => 'd5c457c0b433569aaefd'); 2 | -------------------------------------------------------------------------------- /build/graphiqlQueryComposer.css: -------------------------------------------------------------------------------- 1 | #wp-graphiql-wrapper .docExplorerWrap{background:#fff;box-shadow:0 0 8px rgba(0,0,0,.15);position:relative;z-index:4}#wp-graphiql-wrapper .docExplorerWrap .doc-explorer-title-bar{cursor:default;display:flex;height:34px;line-height:14px;padding:8px 8px 5px;position:relative;-webkit-user-select:none;-moz-user-select:none;user-select:none}#wp-graphiql-wrapper .docExplorerWrap .doc-explorer-title{flex:1 1;font-weight:700;overflow-x:hidden;overflow-y:hidden;padding:5px 0 10px 10px;text-align:center;text-overflow:ellipsis;-webkit-user-select:text;-moz-user-select:text;user-select:text;white-space:nowrap}#wp-graphiql-wrapper .docExplorerWrap .doc-explorer-rhs{position:relative} 2 | -------------------------------------------------------------------------------- /build/index.asset.php: -------------------------------------------------------------------------------- 1 | <?php return array('dependencies' => array('react', 'wp-element', 'wp-hooks'), 'version' => '42b004019b12ba709032'); 2 | -------------------------------------------------------------------------------- /build/style-app-rtl.css: -------------------------------------------------------------------------------- 1 | #graphiql{display:flex;flex:1}#graphiql .spinner{background:none;visibility:visible}#wp-graphiql-wrapper .doc-explorer-title,#wp-graphiql-wrapper .history-title{overflow-x:visible;padding-top:7px}#wp-graphiql-wrapper .docExplorerWrap,#wp-graphiql-wrapper .historyPaneWrap{background:#fff;box-shadow:0 0 8px rgba(0,0,0,.15);position:relative;z-index:3}#wp-graphiql-wrapper .graphiql-container .doc-explorer-back{overflow:hidden} 2 | -------------------------------------------------------------------------------- /build/style-app.css: -------------------------------------------------------------------------------- 1 | #graphiql{display:flex;flex:1}#graphiql .spinner{background:none;visibility:visible}#wp-graphiql-wrapper .doc-explorer-title,#wp-graphiql-wrapper .history-title{overflow-x:visible;padding-top:7px}#wp-graphiql-wrapper .docExplorerWrap,#wp-graphiql-wrapper .historyPaneWrap{background:#fff;box-shadow:0 0 8px rgba(0,0,0,.15);position:relative;z-index:3}#wp-graphiql-wrapper .graphiql-container .doc-explorer-back{overflow:hidden} 2 | -------------------------------------------------------------------------------- /build/updates.asset.php: -------------------------------------------------------------------------------- 1 | <?php return array('dependencies' => array(), 'version' => 'c512025433cfc6193570'); 2 | -------------------------------------------------------------------------------- /cli/README.md: -------------------------------------------------------------------------------- 1 | # CLI Scripts 2 | 3 | These are handy scripts for interacting with WPGraphQL via the command line. 4 | 5 | -------------------------------------------------------------------------------- /constants.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Sets up constants for use throughout the plugin and by other extending plugins. 4 | * 5 | * This is in its own file so that it can be used via the autoloaded classes, but also 6 | * can be pulled in when composer dependencies have not been installed. 7 | * 8 | * @return void 9 | */ 10 | function graphql_setup_constants() { 11 | 12 | // Whether to autoload the files or not. 13 | // This must be defined here and not within the WPGraphQL.php because this constant 14 | // determines whether to autoload classes or not 15 | if ( ! defined( 'WPGRAPHQL_AUTOLOAD' ) ) { 16 | define( 'WPGRAPHQL_AUTOLOAD', true ); 17 | } 18 | 19 | // Plugin version. 20 | if ( ! defined( 'WPGRAPHQL_VERSION' ) ) { 21 | define( 'WPGRAPHQL_VERSION', '2.3.4' ); 22 | } 23 | 24 | // Plugin Folder Path. 25 | if ( ! defined( 'WPGRAPHQL_PLUGIN_DIR' ) ) { 26 | define( 'WPGRAPHQL_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); 27 | } 28 | 29 | // Plugin Root File. 30 | if ( ! defined( 'WPGRAPHQL_PLUGIN_FILE' ) ) { 31 | define( 'WPGRAPHQL_PLUGIN_FILE', WPGRAPHQL_PLUGIN_DIR . '/wp-graphql.php' ); 32 | } 33 | 34 | // The minimum version of PHP this plugin requires to work properly 35 | if ( ! defined( 'GRAPHQL_MIN_PHP_VERSION' ) ) { 36 | define( 'GRAPHQL_MIN_PHP_VERSION', '7.4' ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /deactivation.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Runs when WPGraphQL is de-activated 4 | * 5 | * This cleans up data that WPGraphQL stores 6 | * 7 | * @return void 8 | */ 9 | function graphql_deactivation_callback() { 10 | 11 | if ( ! graphql_can_load_plugin() ) { 12 | return; 13 | } 14 | 15 | // Fire an action when WPGraphQL is de-activating 16 | do_action( 'graphql_deactivate' ); 17 | 18 | // Delete data during activation 19 | delete_graphql_data(); 20 | } 21 | 22 | /** 23 | * Delete data on deactivation 24 | */ 25 | function delete_graphql_data(): void { 26 | 27 | if ( ! class_exists( 'WPGraphQL' ) ) { 28 | return; 29 | } 30 | 31 | // Check if the plugin is set to delete data or not 32 | $delete_data = get_graphql_setting( 'delete_data_on_deactivate' ); 33 | 34 | // If data is not set to delete, stop now 35 | if ( 'on' !== $delete_data ) { 36 | return; 37 | } 38 | 39 | // Delete graphql version 40 | delete_option( 'wp_graphql_version' ); 41 | 42 | // Initialize the settings API 43 | $settings = new WPGraphQL\Admin\Settings\Settings(); 44 | $settings->init(); 45 | $settings->register_settings(); 46 | 47 | // Get all the registered settings fields 48 | $fields = $settings->settings_api->get_settings_fields(); 49 | 50 | // Loop over the registered settings fields and delete the options 51 | if ( ! empty( $fields ) && is_array( $fields ) ) { 52 | foreach ( $fields as $group => $fields ) { 53 | delete_option( $group ); 54 | } 55 | } 56 | 57 | do_action( 'graphql_delete_data' ); 58 | } 59 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.3' 2 | 3 | services: 4 | app: 5 | depends_on: 6 | - app_db 7 | image: wp-graphql:latest-wp${WP_VERSION-6.2}-php${PHP_VERSION-8.2} 8 | volumes: 9 | - '.:/var/www/html/wp-content/plugins/wp-graphql' 10 | - './.log/app:/var/log/apache2' 11 | env_file: 12 | - .env 13 | environment: 14 | WP_URL: http://localhost:8091 15 | USING_XDEBUG: ${USING_XDEBUG:-} 16 | ports: 17 | - '8091:80' 18 | networks: 19 | local: 20 | 21 | app_db: 22 | image: mariadb:10 23 | environment: 24 | MYSQL_ROOT_PASSWORD: root 25 | MYSQL_DATABASE: wordpress 26 | MYSQL_USER: wordpress 27 | MYSQL_PASSWORD: wordpress 28 | ports: 29 | - '3306' 30 | networks: 31 | testing: 32 | local: 33 | 34 | testing: 35 | depends_on: 36 | - app_db 37 | image: wp-graphql-testing:latest-wp${WP_VERSION-6.2}-php${PHP_VERSION-8.2} 38 | volumes: 39 | - '.:/var/www/html/wp-content/plugins/wp-graphql' 40 | - './.log/testing:/var/log/apache2' 41 | env_file: 42 | - .env 43 | environment: 44 | SUITES: ${SUITES:-} 45 | networks: 46 | testing: 47 | 48 | networks: 49 | local: 50 | testing: 51 | -------------------------------------------------------------------------------- /docker/app.entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Run app setup script. 4 | . app-setup.sh 5 | . app-post-setup.sh 6 | 7 | exec "$@" 8 | -------------------------------------------------------------------------------- /docker/app.post-setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Activate wp-graphql 4 | wp plugin activate wp-graphql --allow-root 5 | 6 | # Set pretty permalinks. 7 | wp rewrite structure '/%year%/%monthnum%/%postname%/' --allow-root 8 | 9 | wp db export "${DATA_DUMP_DIR}/dump.sql" --allow-root 10 | 11 | # If maintenance mode is active, de-activate it 12 | if $( wp maintenance-mode is-active --allow-root ); then 13 | echo "Deactivating maintenance mode" 14 | wp maintenance-mode deactivate --allow-root 15 | fi 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/images/application-data-graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/application-data-graph.png -------------------------------------------------------------------------------- /docs/images/categories-delete-not-allowed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/categories-delete-not-allowed.png -------------------------------------------------------------------------------- /docs/images/categories-delete-success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/categories-delete-success.png -------------------------------------------------------------------------------- /docs/images/categories-mutation-create-not-allowed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/categories-mutation-create-not-allowed.png -------------------------------------------------------------------------------- /docs/images/categories-mutation-create-success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/categories-mutation-create-success.png -------------------------------------------------------------------------------- /docs/images/categories-mutation-update-not-allowed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/categories-mutation-update-not-allowed.png -------------------------------------------------------------------------------- /docs/images/categories-mutation-update-success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/categories-mutation-update-success.png -------------------------------------------------------------------------------- /docs/images/categories-query-by-global-id.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/categories-query-by-global-id.png -------------------------------------------------------------------------------- /docs/images/categories-query-edges-nodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/categories-query-edges-nodes.png -------------------------------------------------------------------------------- /docs/images/categories-query-nodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/categories-query-nodes.png -------------------------------------------------------------------------------- /docs/images/comments-mutation-closed-failure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/comments-mutation-closed-failure.png -------------------------------------------------------------------------------- /docs/images/comments-mutation-delete-denied.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/comments-mutation-delete-denied.png -------------------------------------------------------------------------------- /docs/images/comments-mutation-delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/comments-mutation-delete.png -------------------------------------------------------------------------------- /docs/images/comments-mutation-duplicate-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/comments-mutation-duplicate-error.png -------------------------------------------------------------------------------- /docs/images/comments-mutation-not-allowed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/comments-mutation-not-allowed.png -------------------------------------------------------------------------------- /docs/images/comments-mutation-public-user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/comments-mutation-public-user.png -------------------------------------------------------------------------------- /docs/images/comments-mutation-restore-not-allowed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/comments-mutation-restore-not-allowed.png -------------------------------------------------------------------------------- /docs/images/comments-mutation-restore-success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/comments-mutation-restore-success.png -------------------------------------------------------------------------------- /docs/images/comments-mutation-success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/comments-mutation-success.png -------------------------------------------------------------------------------- /docs/images/comments-query-post.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/comments-query-post.png -------------------------------------------------------------------------------- /docs/images/connections-graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/connections-graph.png -------------------------------------------------------------------------------- /docs/images/data-graph-category-term-connections.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/data-graph-category-term-connections.png -------------------------------------------------------------------------------- /docs/images/data-graph-category-terms-connection-complex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/data-graph-category-terms-connection-complex.png -------------------------------------------------------------------------------- /docs/images/data-graph-category-terms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/data-graph-category-terms.png -------------------------------------------------------------------------------- /docs/images/data-graph-hello-world.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/data-graph-hello-world.png -------------------------------------------------------------------------------- /docs/images/data-graph-query-filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/data-graph-query-filter.png -------------------------------------------------------------------------------- /docs/images/debugging-graphql-query-logs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/debugging-graphql-query-logs.png -------------------------------------------------------------------------------- /docs/images/debugging-graphql-response.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/debugging-graphql-response.png -------------------------------------------------------------------------------- /docs/images/debugging-graphql-trace-log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/debugging-graphql-trace-log.png -------------------------------------------------------------------------------- /docs/images/debugging-graphql-unexpected-token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/debugging-graphql-unexpected-token.png -------------------------------------------------------------------------------- /docs/images/debugging-output-graphql-debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/debugging-output-graphql-debug.png -------------------------------------------------------------------------------- /docs/images/debugging-setting-enable-graphql-query-logs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/debugging-setting-enable-graphql-query-logs.png -------------------------------------------------------------------------------- /docs/images/debugging-setting-enable-graphql.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/debugging-setting-enable-graphql.png -------------------------------------------------------------------------------- /docs/images/debugging-setting-graphql-enable-tracing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/debugging-setting-graphql-enable-tracing.png -------------------------------------------------------------------------------- /docs/images/debugging-unexpected-token.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/debugging-unexpected-token.gif -------------------------------------------------------------------------------- /docs/images/extension-graphiql-explorer-custom-type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/extension-graphiql-explorer-custom-type.png -------------------------------------------------------------------------------- /docs/images/extension-graphiql-explorer-search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/extension-graphiql-explorer-search.png -------------------------------------------------------------------------------- /docs/images/extension-query-custom-field.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/extension-query-custom-field.png -------------------------------------------------------------------------------- /docs/images/extension-query-custom-type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/extension-query-custom-type.png -------------------------------------------------------------------------------- /docs/images/extension-wordpress-admin-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/extension-wordpress-admin-screen.png -------------------------------------------------------------------------------- /docs/images/extension-wordpress-plugin-dir.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/extension-wordpress-plugin-dir.png -------------------------------------------------------------------------------- /docs/images/extension-wordpress-plugin-filename.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/extension-wordpress-plugin-filename.png -------------------------------------------------------------------------------- /docs/images/graphiql-auth-switch.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/graphiql-auth-switch.gif -------------------------------------------------------------------------------- /docs/images/graphiql-full-window-mode.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/graphiql-full-window-mode.gif -------------------------------------------------------------------------------- /docs/images/graphiql-ide-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/graphiql-ide-screenshot.png -------------------------------------------------------------------------------- /docs/images/graphiql-query-composer.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/graphiql-query-composer.gif -------------------------------------------------------------------------------- /docs/images/interacting-fetch-graphql-from-browser-console-1024x619.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/interacting-fetch-graphql-from-browser-console-1024x619.gif -------------------------------------------------------------------------------- /docs/images/interacting-wordpress-admin-graphiql.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/interacting-wordpress-admin-graphiql.png -------------------------------------------------------------------------------- /docs/images/intro-graphql-MenuItems.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/intro-graphql-MenuItems.gif -------------------------------------------------------------------------------- /docs/images/intro-graphql-fragments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/intro-graphql-fragments.png -------------------------------------------------------------------------------- /docs/images/media-query-by-global-id.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/media-query-by-global-id.png -------------------------------------------------------------------------------- /docs/images/media-query-by-source-url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/media-query-by-source-url.png -------------------------------------------------------------------------------- /docs/images/media-query-items.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/media-query-items.png -------------------------------------------------------------------------------- /docs/images/media-query-post-featured-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/media-query-post-featured-image.png -------------------------------------------------------------------------------- /docs/images/menus-query-by-global-id.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/menus-query-by-global-id.png -------------------------------------------------------------------------------- /docs/images/menus-query-by-name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/menus-query-by-name.png -------------------------------------------------------------------------------- /docs/images/menus-query-filter-location.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/menus-query-filter-location.png -------------------------------------------------------------------------------- /docs/images/menus-query-items.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/menus-query-items.png -------------------------------------------------------------------------------- /docs/images/mutations-create-post-with-custom-input-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/mutations-create-post-with-custom-input-example.png -------------------------------------------------------------------------------- /docs/images/mutations-custom-input-field-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/mutations-custom-input-field-example.png -------------------------------------------------------------------------------- /docs/images/plugins-query-authenticated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/plugins-query-authenticated.png -------------------------------------------------------------------------------- /docs/images/plugins-query-global-id.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/plugins-query-global-id.png -------------------------------------------------------------------------------- /docs/images/plugins-query-id-without-access.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/plugins-query-id-without-access.png -------------------------------------------------------------------------------- /docs/images/plugins-query-unauthenticated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/plugins-query-unauthenticated.png -------------------------------------------------------------------------------- /docs/images/posts-mutation-create-not-allowed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/posts-mutation-create-not-allowed.png -------------------------------------------------------------------------------- /docs/images/posts-mutation-create-success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/posts-mutation-create-success.png -------------------------------------------------------------------------------- /docs/images/posts-mutation-delete-not-allowed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/posts-mutation-delete-not-allowed.png -------------------------------------------------------------------------------- /docs/images/posts-mutation-delete-success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/posts-mutation-delete-success.png -------------------------------------------------------------------------------- /docs/images/posts-mutation-update-not-allowed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/posts-mutation-update-not-allowed.png -------------------------------------------------------------------------------- /docs/images/posts-mutation-update-success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/posts-mutation-update-success.png -------------------------------------------------------------------------------- /docs/images/posts-query-by-database-id.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/posts-query-by-database-id.png -------------------------------------------------------------------------------- /docs/images/posts-query-by-global-id.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/posts-query-by-global-id.png -------------------------------------------------------------------------------- /docs/images/posts-query-by-slug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/posts-query-by-slug.png -------------------------------------------------------------------------------- /docs/images/posts-query-by-uri.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/posts-query-by-uri.png -------------------------------------------------------------------------------- /docs/images/posts-query-edges-node.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/posts-query-edges-node.png -------------------------------------------------------------------------------- /docs/images/posts-query-filter-by-author.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/posts-query-filter-by-author.png -------------------------------------------------------------------------------- /docs/images/posts-query-filter-by-keyword.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/posts-query-filter-by-keyword.png -------------------------------------------------------------------------------- /docs/images/posts-query-filter-by-title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/posts-query-filter-by-title.png -------------------------------------------------------------------------------- /docs/images/posts-query-nodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/posts-query-nodes.png -------------------------------------------------------------------------------- /docs/images/quick-graphiql-ide-wordpress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/quick-graphiql-ide-wordpress.png -------------------------------------------------------------------------------- /docs/images/quick-graphiql-ide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/quick-graphiql-ide.png -------------------------------------------------------------------------------- /docs/images/quick-graphiql-search-posts.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/quick-graphiql-search-posts.gif -------------------------------------------------------------------------------- /docs/images/quick-wp-graphql-first-query.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/quick-wp-graphql-first-query.gif -------------------------------------------------------------------------------- /docs/images/settings-mutation-authorized.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/settings-mutation-authorized.png -------------------------------------------------------------------------------- /docs/images/settings-mutation-not-authorized.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/settings-mutation-not-authorized.png -------------------------------------------------------------------------------- /docs/images/settings-wordpress-general-page-title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/settings-wordpress-general-page-title.png -------------------------------------------------------------------------------- /docs/images/tags-query-by-name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/tags-query-by-name.png -------------------------------------------------------------------------------- /docs/images/tags-query-by-uri.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/tags-query-by-uri.png -------------------------------------------------------------------------------- /docs/images/tags-query-nodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/tags-query-nodes.png -------------------------------------------------------------------------------- /docs/images/testing-codeception-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/testing-codeception-screenshot.png -------------------------------------------------------------------------------- /docs/images/themes-authenticated-user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/themes-authenticated-user.png -------------------------------------------------------------------------------- /docs/images/themes-not-authenticated-user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/themes-not-authenticated-user.png -------------------------------------------------------------------------------- /docs/images/users-create-success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/users-create-success.png -------------------------------------------------------------------------------- /docs/images/users-create-user-unsuccessful.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/users-create-user-unsuccessful.png -------------------------------------------------------------------------------- /docs/images/users-delete-success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/users-delete-success.png -------------------------------------------------------------------------------- /docs/images/users-delete-unsuccessful.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/users-delete-unsuccessful.png -------------------------------------------------------------------------------- /docs/images/users-mutation-register-disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/users-mutation-register-disabled.png -------------------------------------------------------------------------------- /docs/images/users-mutation-register-success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/users-mutation-register-success.png -------------------------------------------------------------------------------- /docs/images/users-mutation-reset-password-invalid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/users-mutation-reset-password-invalid.png -------------------------------------------------------------------------------- /docs/images/users-query-by-global-id.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/users-query-by-global-id.png -------------------------------------------------------------------------------- /docs/images/users-query.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/users-query.png -------------------------------------------------------------------------------- /docs/images/users-registration-email.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/users-registration-email.png -------------------------------------------------------------------------------- /docs/images/users-update-success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/users-update-success.png -------------------------------------------------------------------------------- /docs/images/users-update-unsuccessful.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/users-update-unsuccessful.png -------------------------------------------------------------------------------- /docs/images/users-wordpress-new-password.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/users-wordpress-new-password.png -------------------------------------------------------------------------------- /docs/images/users-wordpress-reset-password.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/users-wordpress-reset-password.png -------------------------------------------------------------------------------- /docs/images/wpgraphql-acf-search-schema.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/wpgraphql-acf-search-schema.gif -------------------------------------------------------------------------------- /docs/images/wpgraphql-nested-query.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/wpgraphql-nested-query.gif -------------------------------------------------------------------------------- /docs/images/wpgraphql-query-100-posts-graphql.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/wpgraphql-query-100-posts-graphql.png -------------------------------------------------------------------------------- /docs/images/wpgraphql-query-100-posts-rest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/wpgraphql-query-100-posts-rest.png -------------------------------------------------------------------------------- /docs/images/wpgraphql-query-acf-flex.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/wpgraphql-query-acf-flex.gif -------------------------------------------------------------------------------- /docs/images/wpgraphql-query-batch-postman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/wpgraphql-query-batch-postman.png -------------------------------------------------------------------------------- /docs/images/wpgraphql-query-github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/wpgraphql-query-github.png -------------------------------------------------------------------------------- /docs/images/wpgraphql-query-multiple-resources.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/wpgraphql-query-multiple-resources.png -------------------------------------------------------------------------------- /docs/images/wpgraphql-query-types-fields.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/wpgraphql-query-types-fields.png -------------------------------------------------------------------------------- /docs/images/wpgraphql-wordpress-dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/wpgraphql-wordpress-dashboard.png -------------------------------------------------------------------------------- /docs/images/wpgraphql-wordpress-rest-api-acf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/docs/images/wpgraphql-wordpress-rest-api-acf.png -------------------------------------------------------------------------------- /docs/interfaces.md: -------------------------------------------------------------------------------- 1 | --- 2 | uri: "/docs/interfaces/" 3 | title: "Interfaces" 4 | --- 5 | 6 | Add some interesting interfaces here. 7 | -------------------------------------------------------------------------------- /docs/themes.md: -------------------------------------------------------------------------------- 1 | --- 2 | uri: "/docs/themes/" 3 | title: "Themes" 4 | --- 5 | 6 | This page will be most useful for users what are familiar with [GraphQL Concepts](/docs/intro-to-graphql/) and understand the basics of [writing GraphQL Queries](/docs/intro-to-graphql/#queries-and-mutation). 7 | 8 | ## Querying Themes 9 | 10 | WPGraphQL provides support for querying Themes in various ways. 11 | 12 | ### List of Themes 13 | 14 | Below is an example of querying a list of Themes. 15 | 16 | ```graphql 17 | { 18 | themes { 19 | nodes { 20 | id 21 | name 22 | version 23 | } 24 | } 25 | } 26 | ``` 27 | 28 | #### Query from Authenticated User 29 | 30 | Authenticated users with the "edit\_themes" capability can query a list of Themes and see all available themes for the site. 31 | 32 |  33 | 34 | #### Query from Public User 35 | 36 | A public user or a user without "edit\_themes" capability can make the same query and only the active theme will be returned. 37 | 38 | The active theme is considered a public entity in WordPress and can be publicly accessed and WPGraphQL respects this access control right. 39 | 40 |  41 | 42 | ## Mutations 43 | 44 | > WPGraphQL does not currently support mutations for themes. 45 | -------------------------------------------------------------------------------- /docs/widgets.md: -------------------------------------------------------------------------------- 1 | --- 2 | uri: "/docs/widgets/" 3 | title: "Widgets" 4 | --- 5 | 6 | WPGraphQL currently does not support queries or mutations for widgets. 7 | 8 | Widgets don't have a proper server registry so it's difficult to provide formal WPGraphQL support for querying and/or mutating Widgets. 9 | 10 | [Read more about the decision not to officially support widgets](https://github.com/wp-graphql/wp-graphql/issues/20#issuecomment-554426933). 11 | -------------------------------------------------------------------------------- /img/README.md: -------------------------------------------------------------------------------- 1 | # img Directory 2 | 3 | This directory contains images for use in documentation references. This directory is not intended to be used for images that are part of the application UI as this directory is not included in the distributed plugin. For images that are part of the application UI, use the `src/assets` directory. 4 | -------------------------------------------------------------------------------- /img/anatomy-of-request.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/img/anatomy-of-request.png -------------------------------------------------------------------------------- /img/graphiql-ide-example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/img/graphiql-ide-example.gif -------------------------------------------------------------------------------- /img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/img/logo.png -------------------------------------------------------------------------------- /img/wp-example-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/img/wp-example-web.png -------------------------------------------------------------------------------- /img/wp-graphql-logo-square-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/img/wp-graphql-logo-square-512x512.png -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | base = "docs" 3 | publish = "docs/public" 4 | -------------------------------------------------------------------------------- /packages/README.md: -------------------------------------------------------------------------------- 1 | # Packages 2 | 3 | This directory contains the JavaScript packages for WPGraphQL. 4 | 5 | These packages are used to build the tooling that makes up the GraphiQL IDE in the admin. 6 | 7 | ## Running Locally 8 | 9 | If you're working on the GraphiQL App locally, you can follow these steps to run GraphiQL in dev mode: 10 | 11 | ### Install Dependencies 12 | 13 | From the root of the plugin directory, run the following command: 14 | 15 | - `npm install` 16 | 17 | ### Run in Dev Mode 18 | 19 | Running the app in dev mode allows for the changes to the code to be re-built immediately and reduces the time for the feedback loop. You can refresh the WP Admin as you're working and see your changes right away. 20 | 21 | From the root of the plugin directory, run the following command: 22 | 23 | - `npm run start` 24 | 25 | ### Build the app 26 | 27 | Building the app allows for the app to be used without being in "dev" mode. It generates new assets in the build directory which are enqueued by the WordPress admin. You'll want to test your changes in a build to ensure the changes will work for users. 28 | 29 | From the root of the plugin directory, run the following command: 30 | 31 | - `npm run build` 32 | -------------------------------------------------------------------------------- /packages/extensions/Extensions.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | import { __ } from '@wordpress/i18n'; 3 | import PluginCard from './PluginCard'; 4 | 5 | /** 6 | * Extensions component to display the list of WPGraphQL extensions. 7 | * 8 | * @return {JSX.Element} The Extensions component. 9 | */ 10 | const Extensions = () => { 11 | const [extensions, setExtensions] = useState([]); 12 | 13 | useEffect(() => { 14 | if (window.wpgraphqlExtensions && window.wpgraphqlExtensions.extensions) { 15 | setExtensions(window.wpgraphqlExtensions.extensions); 16 | } 17 | }, []); 18 | 19 | return ( 20 | <div className="wp-clearfix"> 21 | <div className="plugin-cards"> 22 | {extensions.map((extension) => ( 23 | <PluginCard key={extension.plugin_url} plugin={extension} /> 24 | ))} 25 | </div> 26 | </div> 27 | ); 28 | }; 29 | 30 | export default Extensions; 31 | -------------------------------------------------------------------------------- /packages/extensions/README.md: -------------------------------------------------------------------------------- 1 | # Extensions 2 | 3 | This directory contains the React app that is enqueue'd in the WordPress admin to display a list of WPGraphQL extensions. 4 | 5 | It reads the list of extensions from the localized json under the name `wpgraphqlExtensions`. 6 | 7 | You can read more about the extensions list in the [Admin Extensions README](../../src/Admin/Extensions/README.md). 8 | 9 | ## Development 10 | 11 | To start the development server, run: 12 | 13 | ```shell 14 | $ npm install && npm start 15 | ``` 16 | 17 | This will run wp-scripts start and start the development server. 18 | 19 | ## Production 20 | 21 | To build the production version of the app, run: 22 | 23 | ```shell 24 | $ npm run build 25 | ``` 26 | 27 | This will run wp-scripts build and create a production-ready build of the app. 28 | 29 | ## Deployment 30 | 31 | The production build of the extensions page is built in a GitHub Action and bundled with the plugin during each release. 32 | -------------------------------------------------------------------------------- /packages/extensions/index.js: -------------------------------------------------------------------------------- 1 | import { createRoot, render } from '@wordpress/element'; 2 | import Extensions from './Extensions'; 3 | import './index.scss'; 4 | 5 | document.addEventListener('DOMContentLoaded', () => { 6 | const container = document.getElementById('wpgraphql-extensions'); 7 | 8 | if ( ! container ) { 9 | return; 10 | } 11 | 12 | /** 13 | * createRoot only exists in WordPress 6.2+. 14 | * 15 | * Once that version is the minimum required, this check can be removed. 16 | */ 17 | if( createRoot ) { 18 | createRoot( container ).render( <Extensions /> ); 19 | } else { 20 | render( <Extensions />, container ); 21 | } 22 | }); 23 | -------------------------------------------------------------------------------- /packages/extensions/index.scss: -------------------------------------------------------------------------------- 1 | .plugin-card .name, .plugin-card .desc, /* For WP <6.5 versions */ 2 | .plugin-card .desc > p { 3 | margin-left: 0; 4 | } 5 | 6 | .plugin-card .name { 7 | margin-bottom: 10px; 8 | } 9 | 10 | .plugin-card-top { 11 | /* This is required to ensure the Settings link does not extend below the bottom of a plugin card on a wide screen. */ 12 | min-height: 110px; 13 | 14 | h2 { 15 | margin: 0; 16 | 17 | } 18 | } 19 | 20 | @media screen and (max-width: 782px) { 21 | .plugin-card-top { 22 | /* Same reason as above, but now the button is taller to make it easier to tap on touch screens. */ 23 | min-height: 110px; 24 | } 25 | } 26 | 27 | .plugin-card .perflab-plugin-experimental { 28 | font-size: 80%; 29 | font-weight: normal; 30 | } 31 | 32 | @media screen and (max-width: 1100px) and (min-width: 782px), (max-width: 480px) { 33 | 34 | .plugin-card .action-links { 35 | margin-left: auto; 36 | } 37 | 38 | /* Make sure the settings link gets spaced out from the Learn more link. */ 39 | .plugin-card .plugin-action-buttons > li:nth-child(3) { 40 | margin-left: 2ex; 41 | border-left: solid 1px; 42 | padding-left: 2ex; 43 | } 44 | } -------------------------------------------------------------------------------- /packages/graphiql-auth-switch/AuthSwitchContext.js: -------------------------------------------------------------------------------- 1 | import { useContext, useState, createContext } from "@wordpress/element"; 2 | const { hooks } = wpGraphiQL; 3 | 4 | export const AuthSwitchContext = createContext(); 5 | 6 | export const useAuthSwitchContext = () => { 7 | return useContext(AuthSwitchContext); 8 | }; 9 | 10 | export const AuthSwitchProvider = ({ children }) => { 11 | const getDefaultState = () => { 12 | const localValue = window?.localStorage.getItem( 13 | "graphiql:usePublicFetcher" 14 | ); 15 | return !(localValue && localValue === "false"); 16 | }; 17 | 18 | const [usePublicFetcher, setUsePublicFetcher] = useState(getDefaultState()); 19 | 20 | const toggleUsePublicFetcher = () => { 21 | const newState = !usePublicFetcher; 22 | window.localStorage.setItem( 23 | "graphiql:usePublicFetcher", 24 | newState.toString() 25 | ); 26 | setUsePublicFetcher(newState); 27 | }; 28 | 29 | const value = hooks.applyFilters( 30 | "graphiql_auth_switch_context_default_value", 31 | { 32 | usePublicFetcher, 33 | setUsePublicFetcher, 34 | toggleUsePublicFetcher, 35 | } 36 | ); 37 | 38 | return ( 39 | <AuthSwitchContext.Provider value={value}> 40 | {children} 41 | </AuthSwitchContext.Provider> 42 | ); 43 | }; 44 | -------------------------------------------------------------------------------- /packages/graphiql-auth-switch/README.md: -------------------------------------------------------------------------------- 1 | # Auth Switch 2 | 3 | The "auth switch" feature allows users to use GraphiQL in an authenticated or non-authenticated state. 4 | 5 | This "extension" hooks into: 6 | 7 | - `graphiql_app`: to provide wrap the app with a custom Context Provider 8 | - `graphiql_toolbar_before_buttons`: to provide the avatar button in the toolbar 9 | - `graphiql_fetcher`: to customize behavior of how GraphiQL fetches the requests 10 | 11 | ## Usage 12 | 13 | When a user clicks the avatar in the GraphiQL Toolbar, it toggles the fetcher to either execute with credentials (authenticated) or without credentials (public / non-authenticated). 14 | 15 | The default state is public. 16 | 17 |  18 | -------------------------------------------------------------------------------- /packages/graphiql-fullscreen-toggle/index.scss: -------------------------------------------------------------------------------- 1 | .graphiql-fullscreen #wp-graphiql-wrapper { 2 | position: fixed; 3 | z-index: 99999; 4 | inset: 0; 5 | padding: 0; 6 | } 7 | 8 | #graphiql-fullscreen-toggle { 9 | height: 30px; 10 | display: flex; 11 | justify-content: center; 12 | align-items: center; 13 | padding: 8px; 14 | } 15 | 16 | .graphiql-fullscreen #wp-graphiql-wrapper .expand-icon, 17 | #wp-graphiql-wrapper .contract-icon { 18 | display: none; 19 | } 20 | .graphiql-fullscreen #wp-graphiql-wrapper .contract-icon { 21 | display: block; 22 | } 23 | -------------------------------------------------------------------------------- /packages/graphiql-query-composer/README.md: -------------------------------------------------------------------------------- 1 | # Query Composer 2 | 3 | The Query Composer allows user to compose queries using a form. 4 | 5 | This is based on the "GraphiQL Explorer" work originally done by OneGraph (https://github.com/OneGraph/graphiql-explorer), 6 | but was rebuilt to be filterable to allow for third parties to customize the field inputs, etc. 7 | -------------------------------------------------------------------------------- /packages/graphiql-query-composer/components/AddOperations.js: -------------------------------------------------------------------------------- 1 | import { Button, Form } from "antd"; 2 | 3 | /** 4 | * Add Operations (queries, mutations, subscriptions) to the Query Builder 5 | * 6 | * @param props 7 | * @returns {JSX.Element} 8 | * @constructor 9 | */ 10 | const AddOperations = (props) => { 11 | const { actionOptions, addOperation } = props; 12 | 13 | const height = actionOptions.length * 45; 14 | 15 | return ( 16 | <> 17 | <div 18 | style={{ 19 | padding: `10px 10px 0 10px`, 20 | borderTop: `1px solid #ccc`, 21 | overflowY: `hidden`, 22 | minHeight: `${height}px`, 23 | }} 24 | > 25 | <Form 26 | name="add-graphql-operation" 27 | className="variable-editor-title graphiql-explorer-actions" 28 | layout="inline" 29 | onSubmit={(event) => event.preventDefault()} 30 | > 31 | {actionOptions.map((action, i) => { 32 | const { type } = action; 33 | 34 | return ( 35 | <Button 36 | key={i} 37 | style={{ marginBottom: `5px`, textTransform: `capitalize` }} 38 | block 39 | type="primary" 40 | onClick={() => addOperation(type)} 41 | > 42 | Add New {type} 43 | </Button> 44 | ); 45 | })} 46 | </Form> 47 | </div> 48 | </> 49 | ); 50 | }; 51 | 52 | export default AddOperations; 53 | -------------------------------------------------------------------------------- /packages/graphiql-query-composer/components/Checkbox.js: -------------------------------------------------------------------------------- 1 | const Checkbox = (props) => { 2 | return props.checked 3 | ? props.styleConfig.checkboxChecked 4 | : props.styleConfig.checkboxUnchecked; 5 | }; 6 | 7 | export default Checkbox; 8 | -------------------------------------------------------------------------------- /packages/graphiql-query-composer/components/ErrorBoundary.js: -------------------------------------------------------------------------------- 1 | import useErrorBoundary from "use-error-boundary"; 2 | 3 | const ErrorBoundary = ({ children }) => { 4 | const { ErrorBoundary, didCatch, error } = useErrorBoundary(); 5 | 6 | if (didCatch) { 7 | console.warn({ 8 | error, 9 | }); 10 | } 11 | 12 | return didCatch ? ( 13 | <div style={{ padding: 18, fontFamily: "sans-serif" }}> 14 | <div>Something went wrong</div> 15 | <details style={{ whiteSpace: "pre-wrap" }}> 16 | {error ? error.message : null} 17 | <br /> 18 | {error.stack ? error.stack : null} 19 | </details> 20 | </div> 21 | ) : ( 22 | <ErrorBoundary>{children}</ErrorBoundary> 23 | ); 24 | }; 25 | 26 | export default ErrorBoundary; 27 | -------------------------------------------------------------------------------- /packages/graphiql-query-composer/components/ScalarInput.js: -------------------------------------------------------------------------------- 1 | import { unwrapInputType } from "../utils/utils"; 2 | import { Input } from "antd"; 3 | const { useRef, useEffect } = wp.element; 4 | 5 | const ScalarInput = (props) => { 6 | let input = useRef(null); 7 | 8 | const _handleChange = (event) => { 9 | props.setArgValue(event, true); 10 | }; 11 | 12 | const { arg, argValue, styleConfig } = props; 13 | const argType = unwrapInputType(arg.type); 14 | const value = typeof argValue.value === "string" ? argValue.value : ""; 15 | const color = 16 | props.argValue.kind === "StringValue" 17 | ? styleConfig.colors.string 18 | : styleConfig.colors.number; 19 | 20 | return ( 21 | <span style={{ color }}> 22 | {argType.name === "String" ? '"' : ""} 23 | <Input 24 | name={arg.name} 25 | style={{ 26 | width: `15ch`, 27 | color, 28 | minHeight: `16px`, 29 | }} 30 | size="small" 31 | ref={(node) => { 32 | input = node; 33 | }} 34 | type="text" 35 | onChange={(e) => { 36 | _handleChange(e); 37 | }} 38 | value={value} 39 | /> 40 | {argType.name === "String" ? '"' : ""} 41 | </span> 42 | ); 43 | }; 44 | 45 | export default ScalarInput; 46 | -------------------------------------------------------------------------------- /packages/graphiql-query-composer/index.scss: -------------------------------------------------------------------------------- 1 | #wp-graphiql-wrapper .docExplorerWrap { 2 | background: white; 3 | box-shadow: 0 0 8px rgb(0 0 0 / 15%); 4 | position: relative; 5 | z-index: 4; 6 | } 7 | 8 | #wp-graphiql-wrapper .docExplorerWrap .doc-explorer-title-bar { 9 | cursor: default; 10 | display: flex; 11 | height: 34px; 12 | line-height: 14px; 13 | padding: 8px 8px 5px; 14 | position: relative; 15 | -webkit-user-select: none; 16 | user-select: none; 17 | } 18 | 19 | #wp-graphiql-wrapper .docExplorerWrap .doc-explorer-title { 20 | flex: 1 1; 21 | font-weight: 700; 22 | overflow-x: hidden; 23 | overflow-y: hidden; 24 | padding: 5px 0 10px 10px; 25 | text-align: center; 26 | text-overflow: ellipsis; 27 | -webkit-user-select: text; 28 | user-select: text; 29 | white-space: nowrap; 30 | } 31 | 32 | #wp-graphiql-wrapper .docExplorerWrap .doc-explorer-rhs { 33 | position: relative; 34 | } 35 | -------------------------------------------------------------------------------- /packages/wpgraphiql/README.md: -------------------------------------------------------------------------------- 1 | # Extensions 2 | 3 | This directory contains features that were built using the extension APIs. 4 | 5 | These features showcase how to use the hooks/filters available in the WPGraphiQL app to provide custom functionality. 6 | -------------------------------------------------------------------------------- /packages/wpgraphiql/app.js: -------------------------------------------------------------------------------- 1 | import { createRoot, render } from "@wordpress/element"; 2 | import "./app.scss"; 3 | import AppWithContext from "./components/App/App.js"; 4 | 5 | /** 6 | * Render the application to the DOM 7 | */ 8 | document.addEventListener('DOMContentLoaded', () => { 9 | const container = document.getElementById('graphiql'); 10 | 11 | if ( ! container ) { 12 | return; 13 | } 14 | 15 | /** 16 | * createRoot only exists in WordPress 6.2+. 17 | * 18 | * Once that version is the minimum required, this check can be removed. 19 | */ 20 | if( createRoot ) { 21 | createRoot( container ).render( <AppWithContext /> ); 22 | } else { 23 | render( <AppWithContext />, container ); 24 | } 25 | }); 26 | -------------------------------------------------------------------------------- /packages/wpgraphiql/app.scss: -------------------------------------------------------------------------------- 1 | @import "~graphiql/graphiql.css"; 2 | 3 | #wpcontent { 4 | padding-left: 0; 5 | } 6 | 7 | #wpbody-content { 8 | padding-bottom: 0; 9 | } 10 | 11 | #wpbody-content .wrap { 12 | margin: 0; 13 | } 14 | 15 | #wpfooter { 16 | display: none; 17 | } 18 | 19 | // Hides the update nags 20 | body:not(.graphiql-fullscreen) #wpbody-content{ 21 | position: sticky; 22 | top: 32px; 23 | margin-bottom: -32px; 24 | } 25 | 26 | #wpbody-content > *:not(.wrap) { 27 | display: none; 28 | } 29 | -------------------------------------------------------------------------------- /packages/wpgraphiql/context/AppContext.test.js: -------------------------------------------------------------------------------- 1 | import { 2 | cleanup, 3 | fireEvent, 4 | render, 5 | screen, 6 | waitFor, 7 | act, 8 | } from "@testing-library/react"; 9 | 10 | describe("AppContext", () => { 11 | test("should render", () => { 12 | expect(true).toBe(true); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /packages/wpgraphiql/data/client.js: -------------------------------------------------------------------------------- 1 | import { ApolloClient, InMemoryCache } from "@apollo/client"; 2 | 3 | export const client = (uri) => { 4 | return new ApolloClient({ 5 | uri, 6 | connectToDevTools: true, 7 | cache: new InMemoryCache({}), 8 | }); 9 | }; 10 | -------------------------------------------------------------------------------- /packages/wpgraphiql/index.js: -------------------------------------------------------------------------------- 1 | import * as GraphQL from "graphql/index.js"; 2 | import { createHooks } from "@wordpress/hooks"; 3 | import { useAppContext, AppContextProvider } from "./context/AppContext"; 4 | 5 | export const hooks = createHooks(); 6 | 7 | window.wpGraphiQL = { 8 | GraphQL, 9 | hooks, 10 | useAppContext, 11 | AppContextProvider, 12 | }; 13 | -------------------------------------------------------------------------------- /packages/wpgraphiql/screens/Extensions/README.md: -------------------------------------------------------------------------------- 1 | # Extensions 2 | 3 | This screen is intended to show extensions that are available to install to enhance / customize WPGraphQL. 4 | 5 | See: https://www.wpgraphql.com/extensions/ 6 | -------------------------------------------------------------------------------- /packages/wpgraphiql/screens/GraphQLDocumentEditor/README.md: -------------------------------------------------------------------------------- 1 | # GraphQL Document Editor 2 | 3 | This screen is an advanced interface that allows users to do full CRUD operations on GraphQL Documents, save them back to WordPress, update document settings such as Cache TTL, description and more. 4 | -------------------------------------------------------------------------------- /packages/wpgraphiql/screens/GraphiQL/style.scss: -------------------------------------------------------------------------------- 1 | #graphiql { 2 | display: flex; 3 | flex: 1; 4 | } 5 | 6 | #graphiql .spinner { 7 | visibility: visible; 8 | background: none; 9 | } 10 | 11 | #wp-graphiql-wrapper .doc-explorer-title, 12 | #wp-graphiql-wrapper .history-title { 13 | overflow-x: visible; 14 | padding-top: 7px; 15 | } 16 | 17 | #wp-graphiql-wrapper .docExplorerWrap, 18 | #wp-graphiql-wrapper .historyPaneWrap { 19 | background: white; 20 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.15); 21 | position: relative; 22 | z-index: 3; 23 | } 24 | 25 | #wp-graphiql-wrapper .graphiql-container .doc-explorer-back { 26 | overflow: hidden; 27 | } 28 | -------------------------------------------------------------------------------- /packages/wpgraphiql/screens/GraphiQL/utils/externalFragments.js: -------------------------------------------------------------------------------- 1 | const { parse } = window.wpGraphiQL.GraphQL; 2 | 3 | /** 4 | * Convert fragment strings to Fragment Definitions for use 5 | * in GraphiQL type hinting 6 | * 7 | * @returns {[]|*[]} 8 | */ 9 | export const getExternalFragments = () => { 10 | const externalFragments = wpGraphiQLSettings?.externalFragments ?? null; 11 | 12 | if (!externalFragments) { 13 | return []; 14 | } 15 | 16 | const fragmentsAsAst = []; 17 | 18 | // Map over the fragments 19 | externalFragments.map((fragment) => { 20 | let parsed; 21 | let parsedDefinition; 22 | 23 | try { 24 | parsed = parse(fragment); 25 | 26 | // Get the fragment definition 27 | parsedDefinition = parsed?.definitions[0] ?? null; 28 | } catch (e) { 29 | // the fragment couldn't be parsed into AST 30 | } 31 | 32 | if (parsedDefinition) { 33 | fragmentsAsAst.push(parsedDefinition); 34 | } 35 | }); 36 | 37 | return fragmentsAsAst; 38 | }; 39 | -------------------------------------------------------------------------------- /packages/wpgraphiql/screens/Help/README.md: -------------------------------------------------------------------------------- 1 | # Help 2 | 3 | This screen provides users quick access to get help with WPGraphQL. 4 | -------------------------------------------------------------------------------- /packages/wpgraphiql/screens/Schema/README.md: -------------------------------------------------------------------------------- 1 | # Schema 2 | 3 | This screen is intended to provide users with helpful tools to understand their WPGraphQL Schema. 4 | 5 | Some ideas: 6 | 7 | - browse the schema as "static" docs 8 | - browse the schema visually (ex: GraphQL Voyager) 9 | - see schema changes over time 10 | - track breaking changes 11 | - understand what GraphQL types are connected to what WordPress types 12 | - ex: select a WordPress type, such as "post_type: Post", then see all the Types in the Schema generated from it (Post, RootQueryToPostConnection, CreatePost...etc) 13 | -------------------------------------------------------------------------------- /packages/wpgraphiql/screens/Settings/README.md: -------------------------------------------------------------------------------- 1 | # Settings 2 | 3 | The intent of this screen is to let users read/configure the settings for how WPGraphQL behaves. 4 | 5 | Currently, these settings exist in a PHP-rendered page, but over time can be migrated here. 6 | -------------------------------------------------------------------------------- /packages/wpgraphiql/utils/fetcher.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Returns the authenticated fetcher 3 | * 4 | * @param endpoint 5 | * @param options 6 | * @returns {function(*=): Promise<*>} 7 | */ 8 | export const getFetcher = (endpoint, options) => { 9 | const { nonce } = options; 10 | 11 | return (params) => { 12 | const headers = { 13 | Accept: "application/json", 14 | "content-type": "application/json", 15 | "X-WP-Nonce": nonce, 16 | }; 17 | 18 | const fetchParams = { 19 | method: "POST", 20 | headers, 21 | body: JSON.stringify(params), 22 | credentials: "include", 23 | }; 24 | 25 | return fetch(endpoint, fetchParams).then((res) => { 26 | return res.json(); 27 | }); 28 | }; 29 | }; 30 | -------------------------------------------------------------------------------- /packages/wpgraphiql/utils/format.js: -------------------------------------------------------------------------------- 1 | const { print, parse } = wpGraphiQL.GraphQL; 2 | 3 | export const isValidQuery = (query) => { 4 | try { 5 | const formattedQuery = print(parse(query)); 6 | return formattedQuery; 7 | } catch (e) { 8 | console.warn( 9 | `# Error parsing query from url query param \n\n "${query}"\n\n` + 10 | e.message 11 | ); 12 | return false; 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /phpcs/WPGraphQL/PHPCS/ruleset.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0"?> 2 | <ruleset name="WPGraphQL" namespace="WPGraphQL\PHPCS"> 3 | <description>Custom PHPCS rules for WPGraphQL</description> 4 | 5 | <!-- Define our sniff directory --> 6 | <config name="installed_paths" value="../../"/> 7 | 8 | <!-- Register our sniffs --> 9 | <rule ref="./Sniffs/Functions/VersionParameterSniff.php"/> 10 | <rule ref="./Sniffs/Commenting/ValidSinceTagSniff.php"/> 11 | </ruleset> -------------------------------------------------------------------------------- /phpstan.neon.dist: -------------------------------------------------------------------------------- 1 | parameters: 2 | # Rules 3 | treatPhpDocTypesAsCertain: false 4 | inferPrivatePropertyTypeFromConstructor: true 5 | checkExplicitMixedMissingReturn: true 6 | checkFunctionNameCase: true 7 | checkInternalClassCaseSensitivity: true 8 | checkTooWideReturnTypesInProtectedAndPublicMethods: true 9 | polluteScopeWithAlwaysIterableForeach: false 10 | polluteScopeWithLoopInitialAssignments: false 11 | reportAlwaysTrueInLastCondition: true 12 | reportStaticMethodSignatures: true 13 | reportWrongPhpDocTypeInVarTag: true 14 | 15 | # Configuration 16 | level: 8 17 | phpVersion: 18 | min: 70400 19 | max: 80300 20 | dynamicConstantNames: 21 | - WPGRAPHQL_AUTOLOAD 22 | stubFiles: 23 | # Simulate added properties 24 | - phpstan/class-wp-post-type.php 25 | - phpstan/class-wp-taxonomy.php 26 | - phpstan/class-wp-dependency.php 27 | bootstrapFiles: 28 | - phpstan/constants.php 29 | - wp-graphql.php 30 | - access-functions.php 31 | - activation.php 32 | - deactivation.php 33 | paths: 34 | - wp-graphql.php 35 | - constants.php 36 | - access-functions.php 37 | - activation.php 38 | - deactivation.php 39 | - src/ 40 | excludePaths: 41 | analyseAndScan: 42 | - node_modules (?) 43 | 44 | -------------------------------------------------------------------------------- /phpstan/class-wp-dependency.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | /** 4 | * @property string $type 5 | */ 6 | class _WP_Dependency {} 7 | -------------------------------------------------------------------------------- /phpstan/class-wp-post-type.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | /** 4 | * @property string $graphql_single_name 5 | * @property string $graphql_plural_name 6 | * @property bool $show_in_graphql 7 | * @property 'interface'|'object'|'union' $graphql_kind 8 | * @property ?callable $graphql_resolve_type 9 | * @property array<string,mixed> $graphql_connections 10 | * @property string[] $graphql_exclude_connections 11 | * @property string[] $graphql_interfaces 12 | * @property string[] $graphql_exclude_interfaces 13 | * @property string[] $graphql_union_types 14 | * @property bool $graphql_register_root_field 15 | * @property bool $graphql_register_root_connection 16 | * @property string[] $graphql_exclude_mutations 17 | * @property array<string,mixed> $graphql_fields 18 | * @property string[] $graphql_exclude_fields 19 | */ 20 | final class WP_Post_Type { 21 | } 22 | -------------------------------------------------------------------------------- /phpstan/class-wp-taxonomy.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | /** 4 | * @property string $graphql_single_name 5 | * @property string $graphql_plural_name 6 | * @property bool $show_in_graphql 7 | * @property 'interface'|'object'|'union' $graphql_kind 8 | * @property ?callable $graphql_resolve_type 9 | * @property array<string,mixed> $graphql_connections 10 | * @property string[] $graphql_exclude_connections 11 | * @property string[] $graphql_interfaces 12 | * @property string[] $graphql_exclude_interfaces 13 | * @property string[] $graphql_union_types 14 | * @property bool $graphql_register_root_field 15 | * @property bool $graphql_register_root_connection 16 | * @property string[] $graphql_exclude_mutations 17 | * @property array<string,mixed> $graphql_fields 18 | * @property string[] $graphql_exclude_fields 19 | */ 20 | final class WP_Taxonomy { 21 | } 22 | -------------------------------------------------------------------------------- /phpstan/constants.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Constants defined in this file are to help phpstan analyze code where constants outside the plugin (WordPress core constants, etc) are being used 4 | */ 5 | 6 | define( 'WPGRAPHQL_PLUGIN_URL', true ); 7 | define( 'WPGRAPHQL_PLUGIN_DIR', './' ); 8 | define( 'WPGRAPHQL_AUTOLOAD', false ); 9 | define( 'PHPSTAN', true ); 10 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | <phpunit 2 | bootstrap="tests/bootstrap.php" 3 | backupGlobals="false" 4 | colors="true" 5 | convertErrorsToExceptions="true" 6 | convertNoticesToExceptions="true" 7 | convertWarningsToExceptions="true" 8 | > 9 | <groups> 10 | <exclude> 11 | <group>ajax</group> 12 | </exclude> 13 | <exclude> 14 | <group>external-http</group> 15 | </exclude> 16 | <exclude> 17 | <group>ms-files</group> 18 | </exclude> 19 | </groups> 20 | <testsuites> 21 | <testsuite name="WPGraphQL Test Suite"> 22 | <directory prefix="test-" suffix=".php">./tests/</directory> 23 | </testsuite> 24 | </testsuites> 25 | <logging> 26 | <log type="coverage-clover" target="build/logs/clover.xml"/> 27 | </logging> 28 | <filter> 29 | <whitelist processUncoveredFilesFromWhitelist="true"> 30 | <file>./wp-graphql.php</file> 31 | <file>./access-functions.php</file> 32 | <directory suffix=".php">./src/</directory> 33 | </whitelist> 34 | </filter> 35 | </phpunit> 36 | -------------------------------------------------------------------------------- /scripts/utils/format-pr-body.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Helper script to format PR body content for use in changeset generation 3 | */ 4 | 5 | /** 6 | * Format PR body content by removing HTML comments and escaping special characters 7 | * @param {string} content The PR body content to format 8 | * @returns {string} The formatted content 9 | */ 10 | function formatPrBody(content) { 11 | if (!content) { 12 | return ''; 13 | } 14 | 15 | // Remove HTML comments and their content using regex 16 | // This handles both single-line and multi-line comments 17 | let formatted = content 18 | .replace(/<!--[\s\S]*?-->/g, '') // Remove HTML comments 19 | .replace(/^[\s\r\n]+|[\s\r\n]+$/g, ''); // Trim whitespace 20 | 21 | return formatted; 22 | } 23 | 24 | // Handle both module import and command-line usage 25 | if (require.main === module) { 26 | // When run from command line 27 | const content = process.argv[2]; 28 | if (!content) { 29 | console.error('Error: No content provided'); 30 | process.exit(1); 31 | } 32 | console.log(formatPrBody(content)); 33 | } else { 34 | // When imported as a module 35 | module.exports = formatPrBody; 36 | } -------------------------------------------------------------------------------- /src/Admin/GraphiQL/README.md: -------------------------------------------------------------------------------- 1 | # GraphiQL IDE 2 | 3 | [GraphiQL IDE](https://github.com/graphql/graphiql) is a web based IDE interface for interacting with GraphQL APIs. 4 | 5 | This implementation is tailored to work specifically with WPGraphQL. 6 | -------------------------------------------------------------------------------- /src/Admin/README.md: -------------------------------------------------------------------------------- 1 | # WPGraphQL Admin 2 | 3 | This directory is intended to include admin UI such as WPGraphQL Settings pages, GraphiQL, etc. 4 | -------------------------------------------------------------------------------- /src/Connection/Comments.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Connection; 4 | 5 | /** 6 | * Deprecated class for backwards compatibility. 7 | */ 8 | class Comments extends \WPGraphQL\Type\Connection\Comments { 9 | /** 10 | * {@inheritDoc} 11 | * 12 | * @deprecated 1.13.0 13 | */ 14 | public static function register_connections() { 15 | _deprecated_function( __METHOD__, '1.13.0', '\WPGraphQL\Type\Connection\Comments::register_connections' ); 16 | parent::register_connections(); 17 | } 18 | 19 | /** 20 | * {@inheritDoc} 21 | * 22 | * @deprecated 1.13.0 23 | */ 24 | public static function get_connection_config( $args = [] ) { 25 | _deprecated_function( __METHOD__, '1.13.0', '\WPGraphQL\Type\Connection\Comments::get_connection_config' ); 26 | return parent::get_connection_config( $args ); 27 | } 28 | 29 | /** 30 | * {@inheritDoc} 31 | * 32 | * @deprecated 1.13.0 33 | */ 34 | public static function get_connection_args() { 35 | _deprecated_function( __METHOD__, '1.13.0', '\WPGraphQL\Type\Connection\Comments::get_connection_args' ); 36 | return parent::get_connection_args(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Connection/MenuItems.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Connection; 4 | 5 | /** 6 | * Deprecated class for backwards compatibility. 7 | */ 8 | class MenuItems extends \WPGraphQL\Type\Connection\MenuItems { 9 | /** 10 | * {@inheritDoc} 11 | * 12 | * @deprecated 1.13.0 13 | */ 14 | public static function register_connections() { 15 | _deprecated_function( __METHOD__, '1.13.0', '\WPGraphQL\Type\Connection\MenuItems::register_connections' ); 16 | parent::register_connections(); 17 | } 18 | 19 | /** 20 | * {@inheritDoc} 21 | * 22 | * @deprecated 1.13.0 23 | */ 24 | public static function get_connection_config( $args = [] ) { 25 | _deprecated_function( __METHOD__, '1.13.0', '\WPGraphQL\Type\Connection\MenuItems::get_connection_config' ); 26 | return parent::get_connection_config( $args ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Connection/PostObjects.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Connection; 4 | 5 | /** 6 | * Deprecated class for backwards compatibility. 7 | */ 8 | class PostObjects extends \WPGraphQL\Type\Connection\PostObjects { 9 | /** 10 | * {@inheritDoc} 11 | * 12 | * @deprecated 1.13.0 13 | */ 14 | public static function register_connections() { 15 | _deprecated_function( __METHOD__, '1.13.0', '\WPGraphQL\Type\Connection\PostObjects::register_connections' ); 16 | parent::register_connections(); 17 | } 18 | 19 | /** 20 | * {@inheritDoc} 21 | * 22 | * @deprecated 1.13.0 23 | */ 24 | public static function get_connection_config( $graphql_object, $args = [] ) { 25 | _deprecated_function( __METHOD__, '1.13.0', '\WPGraphQL\Type\Connection\PostObjects::get_connection_config' ); 26 | return parent::get_connection_config( $graphql_object, $args ); 27 | } 28 | 29 | /** 30 | * {@inheritDoc} 31 | * 32 | * @deprecated 1.13.0 33 | */ 34 | public static function get_connection_args( $args = [], $post_type_object = null ) { 35 | _deprecated_function( __METHOD__, '1.13.0', '\WPGraphQL\Type\Connection\PostObjects::get_connection_args' ); 36 | return parent::get_connection_args( $args, $post_type_object ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Connection/Taxonomies.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Connection; 4 | 5 | /** 6 | * Deprecated class for backwards compatibility. 7 | */ 8 | class Taxonomies extends \WPGraphQL\Type\Connection\Taxonomies { 9 | /** 10 | * {@inheritDoc} 11 | * 12 | * @deprecated 1.13.0 13 | */ 14 | public static function register_connections() { 15 | _deprecated_function( __METHOD__, '1.13.0', '\WPGraphQL\Type\Connection\Taxonomies::register_connections' ); 16 | parent::register_connections(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Connection/TermObjects.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Connection; 4 | 5 | /** 6 | * Deprecated class for backwards compatibility. 7 | */ 8 | class TermObjects extends \WPGraphQL\Type\Connection\TermObjects { 9 | /** 10 | * {@inheritDoc} 11 | * 12 | * @deprecated 1.13.0 13 | */ 14 | public static function register_connections() { 15 | _deprecated_function( __METHOD__, '1.13.0', '\WPGraphQL\Type\Connection\TermObjects::register_connections' ); 16 | parent::register_connections(); 17 | } 18 | 19 | /** 20 | * {@inheritDoc} 21 | * 22 | * @deprecated 1.13.0 23 | */ 24 | public static function get_connection_config( $tax_object, $args = [] ) { 25 | _deprecated_function( __METHOD__, '1.13.0', '\WPGraphQL\Type\Connection\TermObjects::get_connection_config' ); 26 | return parent::get_connection_config( $tax_object, $args ); 27 | } 28 | 29 | /** 30 | * {@inheritDoc} 31 | * 32 | * @deprecated 1.13.0 33 | */ 34 | public static function get_connection_args( $args = [] ) { 35 | _deprecated_function( __METHOD__, '1.13.0', '\WPGraphQL\Type\Connection\TermObjects::get_connection_args' ); 36 | return parent::get_connection_args( $args ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Connection/Users.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Connection; 4 | 5 | /** 6 | * Deprecated class for backwards compatibility. 7 | */ 8 | class Users extends \WPGraphQL\Type\Connection\Users { 9 | /** 10 | * {@inheritDoc} 11 | * 12 | * @deprecated 1.13.0 13 | */ 14 | public static function register_connections() { 15 | _deprecated_function( __METHOD__, '1.13.0', '\WPGraphQL\Type\Connection\Users::register_connections' ); 16 | parent::register_connections(); 17 | } 18 | 19 | /** 20 | * {@inheritDoc} 21 | * 22 | * @deprecated 1.13.0 23 | */ 24 | public static function get_connection_args() { 25 | _deprecated_function( __METHOD__, '1.13.0', '\WPGraphQL\Type\Connection\Users::get_connection_args' ); 26 | return parent::get_connection_args(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Data/Connection/MenuConnectionResolver.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Data\Connection; 4 | 5 | /** 6 | * Class MenuConnectionResolver 7 | * 8 | * @package WPGraphQL\Data\Connection 9 | */ 10 | class MenuConnectionResolver extends TermObjectConnectionResolver { 11 | 12 | /** 13 | * {@inheritDoc} 14 | * 15 | * @throws \Exception 16 | */ 17 | protected function prepare_query_args( array $args ): array { 18 | $term_args = [ 19 | 'hide_empty' => false, 20 | 'include' => [], 21 | 'taxonomy' => 'nav_menu', 22 | 'fields' => 'ids', 23 | ]; 24 | 25 | if ( ! empty( $args['where']['slug'] ) ) { 26 | $term_args['slug'] = $args['where']['slug']; 27 | $term_args['include'] = null; 28 | } 29 | 30 | $theme_locations = get_nav_menu_locations(); 31 | 32 | // If a location is specified in the args, use it 33 | if ( ! empty( $args['where']['location'] ) ) { 34 | // Exclude unset and non-existent locations 35 | $term_args['include'] = ! empty( $theme_locations[ $args['where']['location'] ] ) ? $theme_locations[ $args['where']['location'] ] : -1; 36 | // If the current user cannot edit theme options 37 | } elseif ( ! current_user_can( 'edit_theme_options' ) ) { 38 | $term_args['include'] = array_values( $theme_locations ); 39 | } 40 | 41 | if ( ! empty( $args['where']['id'] ) ) { 42 | $term_args['include'] = $args['where']['id']; 43 | } 44 | 45 | $query_args = parent::prepare_query_args( $args ); 46 | 47 | return array_merge( $query_args, $term_args ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Data/Connection/ThemeConnectionResolver.php: -------------------------------------------------------------------------------- 1 | <?php 2 | namespace WPGraphQL\Data\Connection; 3 | 4 | /** 5 | * Class ThemeConnectionResolver 6 | * 7 | * @package WPGraphQL\Data\Resolvers 8 | * @since 0.5.0 9 | * @extends \WPGraphQL\Data\Connection\AbstractConnectionResolver<string[]> 10 | */ 11 | class ThemeConnectionResolver extends AbstractConnectionResolver { 12 | /** 13 | * {@inheritDoc} 14 | */ 15 | public function get_ids_from_query() { 16 | /** 17 | * @todo This is for b/c. We can just use $this->get_query(). 18 | */ 19 | $queried = isset( $this->query ) ? $this->query : $this->get_query(); 20 | 21 | $ids = []; 22 | 23 | if ( empty( $queried ) ) { 24 | return $ids; 25 | } 26 | 27 | foreach ( $queried as $key => $item ) { 28 | $ids[ $key ] = $item; 29 | } 30 | 31 | return $ids; 32 | } 33 | 34 | /** 35 | * {@inheritDoc} 36 | */ 37 | protected function prepare_query_args( array $args ): array { 38 | return [ 39 | 'allowed' => null, 40 | ]; 41 | } 42 | 43 | /** 44 | * {@inheritDoc} 45 | */ 46 | protected function query( array $query_args ) { 47 | return array_keys( wp_get_themes( $query_args ) ); 48 | } 49 | 50 | /** 51 | * {@inheritDoc} 52 | */ 53 | protected function loader_name(): string { 54 | return 'theme'; 55 | } 56 | 57 | /** 58 | * {@inheritDoc} 59 | */ 60 | public function is_valid_offset( $offset ) { 61 | $theme = wp_get_theme( $offset ); 62 | return $theme->exists(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Data/Loader/CommentAuthorLoader.php: -------------------------------------------------------------------------------- 1 | <?php 2 | namespace WPGraphQL\Data\Loader; 3 | 4 | use WPGraphQL\Model\CommentAuthor; 5 | 6 | /** 7 | * Class CommentAuthorLoader 8 | * 9 | * @package WPGraphQL\Data\Loader 10 | */ 11 | class CommentAuthorLoader extends AbstractDataLoader { 12 | 13 | /** 14 | * {@inheritDoc} 15 | * 16 | * @return ?\WPGraphQL\Model\CommentAuthor 17 | */ 18 | protected function get_model( $entry, $key ) { 19 | if ( ! $entry instanceof \WP_Comment ) { 20 | return null; 21 | } 22 | 23 | return new CommentAuthor( $entry ); 24 | } 25 | 26 | /** 27 | * {@inheritDoc} 28 | * 29 | * @param int[] $keys Array of IDs to load 30 | */ 31 | public function loadKeys( array $keys ) { 32 | /** 33 | * Prepare the args for the query. We're provided a specific set of IDs of comments 34 | * so we want to query as efficiently as possible with as little overhead to get the comment 35 | * objects. No need to count the rows, etc. 36 | */ 37 | $args = [ 38 | 'comment__in' => $keys, 39 | 'orderby' => 'comment__in', 40 | 'number' => count( $keys ), 41 | 'no_found_rows' => true, 42 | 'count' => false, 43 | ]; 44 | 45 | /** 46 | * Execute the query. Call get_comments() to add them to the cache. 47 | */ 48 | $query = new \WP_Comment_Query( $args ); 49 | $query->get_comments(); 50 | $loaded = []; 51 | foreach ( $keys as $key ) { 52 | $loaded[ $key ] = \WP_Comment::get_instance( $key ); 53 | } 54 | return $loaded; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Data/Loader/CommentLoader.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Data\Loader; 4 | 5 | use WPGraphQL\Model\Comment; 6 | 7 | /** 8 | * Class CommentLoader 9 | * 10 | * @package WPGraphQL\Data\Loader 11 | */ 12 | class CommentLoader extends AbstractDataLoader { 13 | 14 | /** 15 | * {@inheritDoc} 16 | * 17 | * @return ?\WPGraphQL\Model\Comment 18 | * @throws \Exception 19 | */ 20 | protected function get_model( $entry, $key ) { 21 | if ( ! $entry instanceof \WP_Comment ) { 22 | return null; 23 | } 24 | 25 | $comment_model = new Comment( $entry ); 26 | if ( empty( $comment_model->fields ) ) { 27 | return null; 28 | } 29 | 30 | return $comment_model; 31 | } 32 | 33 | /** 34 | * {@inheritDoc} 35 | * 36 | * @param int[] $keys Array of IDs to load 37 | */ 38 | public function loadKeys( array $keys = [] ) { 39 | 40 | /** 41 | * Prepare the args for the query. We're provided a specific set of IDs of comments 42 | * so we want to query as efficiently as possible with as little overhead to get the comment 43 | * objects. No need to count the rows, etc. 44 | */ 45 | $args = [ 46 | 'comment__in' => $keys, 47 | 'orderby' => 'comment__in', 48 | 'number' => count( $keys ), 49 | 'no_found_rows' => true, 50 | 'count' => false, 51 | ]; 52 | 53 | /** 54 | * Execute the query. Call get_comments() to add them to the cache. 55 | */ 56 | $query = new \WP_Comment_Query( $args ); 57 | $query->get_comments(); 58 | $loaded = []; 59 | foreach ( $keys as $key ) { 60 | $loaded[ $key ] = \WP_Comment::get_instance( $key ); 61 | } 62 | return $loaded; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Data/Loader/EnqueuedScriptLoader.php: -------------------------------------------------------------------------------- 1 | <?php 2 | namespace WPGraphQL\Data\Loader; 3 | 4 | /** 5 | * Class EnqueuedScriptLoader 6 | * 7 | * @package WPGraphQL\Data\Loader 8 | */ 9 | class EnqueuedScriptLoader extends AbstractDataLoader { 10 | 11 | /** 12 | * {@inheritDoc} 13 | * 14 | * @param string[] $keys Array of script handles to load 15 | * 16 | * @return array<string,mixed> 17 | */ 18 | public function loadKeys( array $keys ) { 19 | /** @var \WP_Scripts $wp_scripts */ 20 | global $wp_scripts; 21 | 22 | $loaded = []; 23 | foreach ( $keys as $key ) { 24 | if ( isset( $wp_scripts->registered[ $key ] ) ) { 25 | $script = $wp_scripts->registered[ $key ]; 26 | $script->type = 'EnqueuedScript'; 27 | $loaded[ $key ] = $script; 28 | } else { 29 | $loaded[ $key ] = null; 30 | } 31 | } 32 | return $loaded; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Data/Loader/EnqueuedStylesheetLoader.php: -------------------------------------------------------------------------------- 1 | <?php 2 | namespace WPGraphQL\Data\Loader; 3 | 4 | /** 5 | * Class EnqueuedStylesheetLoader 6 | * 7 | * @package WPGraphQL\Data\Loader 8 | */ 9 | class EnqueuedStylesheetLoader extends AbstractDataLoader { 10 | 11 | /** 12 | * {@inheritDoc} 13 | * 14 | * @param string[] $keys Array of stylesheet handles to load 15 | * 16 | * @return array<string,mixed> 17 | */ 18 | public function loadKeys( array $keys ) { 19 | global $wp_styles; 20 | $loaded = []; 21 | foreach ( $keys as $key ) { 22 | if ( isset( $wp_styles->registered[ $key ] ) ) { 23 | $stylesheet = $wp_styles->registered[ $key ]; 24 | $stylesheet->type = 'EnqueuedStylesheet'; 25 | $loaded[ $key ] = $stylesheet; 26 | } else { 27 | $loaded[ $key ] = null; 28 | } 29 | } 30 | return $loaded; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Data/Loader/PostTypeLoader.php: -------------------------------------------------------------------------------- 1 | <?php 2 | namespace WPGraphQL\Data\Loader; 3 | 4 | use WPGraphQL\Model\PostType; 5 | 6 | /** 7 | * Class PostTypeLoader 8 | * 9 | * @package WPGraphQL\Data\Loader 10 | */ 11 | class PostTypeLoader extends AbstractDataLoader { 12 | 13 | /** 14 | * {@inheritDoc} 15 | * 16 | * @param mixed|\WP_Post_Type $entry The Post Type Object 17 | * 18 | * @return \WPGraphQL\Model\PostType 19 | */ 20 | protected function get_model( $entry, $key ) { 21 | return new PostType( $entry ); 22 | } 23 | 24 | /** 25 | * {@inheritDoc} 26 | * 27 | * @param string[] $keys 28 | * @return array<string,\WP_Post_Type|null> 29 | */ 30 | public function loadKeys( array $keys ) { 31 | $post_types = \WPGraphQL::get_allowed_post_types( 'objects' ); 32 | 33 | if ( empty( $post_types ) ) { 34 | return []; 35 | } 36 | 37 | $loaded = []; 38 | 39 | foreach ( $keys as $key ) { 40 | if ( isset( $post_types[ $key ] ) ) { 41 | $loaded[ $key ] = $post_types[ $key ]; 42 | } else { 43 | $loaded[ $key ] = null; 44 | } 45 | } 46 | 47 | return $loaded; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Data/Loader/README.md: -------------------------------------------------------------------------------- 1 | # Data Loaders 2 | 3 | This directory contains classes related to data loading. 4 | 5 | The concept comes from the formal DataLoader library. 6 | 7 | WordPress already does some batching and caching, so implementing DataLoader straight 8 | up actually leads to _increased_ queries in WPGraphQL, so this approach 9 | makes use of some custom batch load functions and Deferred resolvers, provided 10 | by GraphQL-PHP to reduce the number of queries needed in many cases. 11 | -------------------------------------------------------------------------------- /src/Data/Loader/TaxonomyLoader.php: -------------------------------------------------------------------------------- 1 | <?php 2 | namespace WPGraphQL\Data\Loader; 3 | 4 | use WPGraphQL\Model\Taxonomy; 5 | 6 | /** 7 | * Class TaxonomyLoader 8 | * 9 | * @package WPGraphQL\Data\Loader 10 | */ 11 | class TaxonomyLoader extends AbstractDataLoader { 12 | 13 | /** 14 | * {@inheritDoc} 15 | * 16 | * @param mixed|\WP_Taxonomy $entry The Taxonomy Object 17 | * 18 | * @return \WPGraphQL\Model\Taxonomy 19 | */ 20 | protected function get_model( $entry, $key ) { 21 | return new Taxonomy( $entry ); 22 | } 23 | 24 | /** 25 | * {@inheritDoc} 26 | * 27 | * @param string[] $keys 28 | * 29 | * @return array<string,\WP_Taxonomy|null> 30 | */ 31 | public function loadKeys( array $keys ) { 32 | $taxonomies = \WPGraphQL::get_allowed_taxonomies( 'objects' ); 33 | 34 | if ( empty( $taxonomies ) ) { 35 | return []; 36 | } 37 | 38 | $loaded = []; 39 | foreach ( $keys as $key ) { 40 | if ( isset( $taxonomies[ $key ] ) ) { 41 | $loaded[ $key ] = $taxonomies[ $key ]; 42 | } else { 43 | $loaded[ $key ] = null; 44 | } 45 | } 46 | 47 | return $loaded; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Data/Loader/ThemeLoader.php: -------------------------------------------------------------------------------- 1 | <?php 2 | namespace WPGraphQL\Data\Loader; 3 | 4 | use WPGraphQL\Model\Theme; 5 | 6 | /** 7 | * Class ThemeLoader 8 | * 9 | * @package WPGraphQL\Data\Loader 10 | */ 11 | class ThemeLoader extends AbstractDataLoader { 12 | 13 | /** 14 | * {@inheritDoc} 15 | * 16 | * @param mixed|\WP_Theme $entry The User Role object 17 | * 18 | * @return \WPGraphQL\Model\Theme 19 | */ 20 | protected function get_model( $entry, $key ) { 21 | return new Theme( $entry ); 22 | } 23 | 24 | /** 25 | * {@inheritDoc} 26 | * 27 | * @return array<int|string,?\WP_Theme> 28 | */ 29 | public function loadKeys( array $keys ) { 30 | $themes = wp_get_themes(); 31 | $loaded = []; 32 | 33 | if ( is_array( $themes ) && ! empty( $themes ) ) { 34 | foreach ( $keys as $key ) { 35 | $loaded[ $key ] = null; 36 | 37 | if ( isset( $themes[ $key ] ) ) { 38 | $stylesheet = $themes[ $key ]->get_stylesheet(); 39 | $theme = wp_get_theme( $stylesheet ); 40 | if ( $theme->exists() ) { 41 | $loaded[ $key ] = $theme; 42 | } else { 43 | $loaded[ $key ] = null; 44 | } 45 | } 46 | } 47 | } 48 | 49 | return $loaded; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Data/Loader/UserRoleLoader.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Data\Loader; 4 | 5 | use WPGraphQL\Model\UserRole; 6 | 7 | /** 8 | * Class UserRoleLoader 9 | * 10 | * @package WPGraphQL\Data\Loader 11 | */ 12 | class UserRoleLoader extends AbstractDataLoader { 13 | 14 | /** 15 | * {@inheritDoc} 16 | * 17 | * @return \WPGraphQL\Model\UserRole 18 | */ 19 | protected function get_model( $entry, $key ) { 20 | return new UserRole( $entry ); 21 | } 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | public function loadKeys( array $keys ) { 27 | $wp_roles = wp_roles()->roles; 28 | 29 | $loaded = []; 30 | if ( ! empty( $wp_roles ) && is_array( $wp_roles ) ) { 31 | foreach ( $keys as $key ) { 32 | if ( isset( $wp_roles[ $key ] ) ) { 33 | $role = $wp_roles[ $key ]; 34 | $role['slug'] = $key; 35 | $role['id'] = $key; 36 | $role['displayName'] = $role['name']; 37 | $role['name'] = $key; 38 | $loaded[ $key ] = $role; 39 | } else { 40 | $loaded[ $key ] = null; 41 | } 42 | } 43 | } 44 | 45 | return $loaded; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Data/README.md: -------------------------------------------------------------------------------- 1 | # Data 2 | 3 | Methods for reading and writing data should live here. The "DataSource" class serves as a factory for methods 4 | that handle the fetching/writing of data. -------------------------------------------------------------------------------- /src/Mutation/README.md: -------------------------------------------------------------------------------- 1 | # Mutation 2 | This directory contains registrations for mutations. 3 | 4 | In GraphQL the `mutation` keyword signifies that something in the graph will be changing as a result of the request. 5 | 6 | This directory contains registrations for mutations. 7 | 8 | Learn more about GraphQL mutations here: https://graphql.org/learn/queries/#mutations 9 | -------------------------------------------------------------------------------- /src/Server/ValidationRules/DisableIntrospection.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Server\ValidationRules; 4 | 5 | /** 6 | * Class DisableIntrospection 7 | * 8 | * @package WPGraphQL\Server\ValidationRules 9 | */ 10 | class DisableIntrospection extends \GraphQL\Validator\Rules\DisableIntrospection { 11 | 12 | /** 13 | * DisableIntrospection constructor. 14 | */ 15 | public function __construct() { 16 | $should_be_enabled = $this->should_be_enabled(); 17 | parent::__construct( $should_be_enabled ? self::ENABLED : self::DISABLED ); 18 | } 19 | 20 | /** 21 | * Determines whether the DisableIntrospection rule should be disabled. 22 | */ 23 | public function should_be_enabled(): bool { 24 | if ( ! get_current_user_id() && ! \WPGraphQL::debug() && 'off' === get_graphql_setting( 'public_introspection_enabled', 'off' ) ) { 25 | return true; 26 | } 27 | return false; 28 | } 29 | 30 | /** 31 | * Returns a helpful message when introspection is disabled and an introspection query is attempted. 32 | */ 33 | public static function introspectionDisabledMessage(): string { 34 | return __( 'The query contained __schema or __type, however GraphQL introspection is not allowed for public requests by default. Public introspection can be enabled under the WPGraphQL Settings.', 'wp-graphql' ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Type/Connection/README.md: -------------------------------------------------------------------------------- 1 | # Connections 2 | 3 | This directory stores registrations of connections for the Schema. 4 | 5 | The filename represents the Type the connections are going TO. 6 | 7 | For example, `Comments.php` registers connections from other types TO the Comment type, such as RootQueryToCommentConnection and UserToCommentConnection 8 | 9 | Said registered connections enable queries like so: 10 | 11 | ### RootQueryToCommentConnection 12 | ``` 13 | { 14 | comments { 15 | edges { 16 | node { 17 | id 18 | content 19 | } 20 | } 21 | } 22 | } 23 | ``` 24 | 25 | ### UserToCommentConnection 26 | ``` 27 | { 28 | users { 29 | edges { 30 | node { 31 | comments { 32 | edges { 33 | node { 34 | id 35 | content 36 | } 37 | } 38 | } 39 | } 40 | } 41 | } 42 | } 43 | ``` 44 | -------------------------------------------------------------------------------- /src/Type/Connection/Taxonomies.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Type\Connection; 4 | 5 | use WPGraphQL\Data\Connection\TaxonomyConnectionResolver; 6 | use WPGraphQL\Model\PostType; 7 | 8 | class Taxonomies { 9 | 10 | /** 11 | * Registers connections to the Taxonomy type 12 | * 13 | * @return void 14 | */ 15 | public static function register_connections() { 16 | register_graphql_connection( 17 | [ 18 | 'fromType' => 'RootQuery', 19 | 'toType' => 'Taxonomy', 20 | 'fromFieldName' => 'taxonomies', 21 | 'resolve' => static function ( $source, $args, $context, $info ) { 22 | $resolver = new TaxonomyConnectionResolver( $source, $args, $context, $info ); 23 | return $resolver->get_connection(); 24 | }, 25 | ] 26 | ); 27 | 28 | register_graphql_connection( 29 | [ 30 | 'fromType' => 'ContentType', 31 | 'toType' => 'Taxonomy', 32 | 'fromFieldName' => 'connectedTaxonomies', 33 | 'resolve' => static function ( PostType $source, $args, $context, $info ) { 34 | if ( empty( $source->taxonomies ) ) { 35 | return null; 36 | } 37 | $resolver = new TaxonomyConnectionResolver( $source, $args, $context, $info ); 38 | $resolver->set_query_arg( 'in', $source->taxonomies ); 39 | return $resolver->get_connection(); 40 | }, 41 | ] 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Type/Enum/AvatarRatingEnum.php: -------------------------------------------------------------------------------- 1 | <?php 2 | namespace WPGraphQL\Type\Enum; 3 | 4 | class AvatarRatingEnum { 5 | 6 | /** 7 | * Register the AvatarRatingEnum Type to the Schema 8 | * 9 | * @return void 10 | */ 11 | public static function register_type() { 12 | register_graphql_enum_type( 13 | 'AvatarRatingEnum', 14 | [ 15 | 'description' => static function () { 16 | return __( 'Content rating filter for user avatars. Determines the maximum maturity level of avatars to display, following standard content rating classifications (G, PG, R, X).', 'wp-graphql' ); 17 | }, 18 | 'values' => [ 19 | 'G' => [ 20 | 'description' => static function () { 21 | return __( 'Indicates a G level avatar rating level.', 'wp-graphql' ); 22 | }, 23 | 'value' => 'G', 24 | ], 25 | 'PG' => [ 26 | 'description' => static function () { 27 | return __( 'Indicates a PG level avatar rating level.', 'wp-graphql' ); 28 | }, 29 | 'value' => 'PG', 30 | ], 31 | 'R' => [ 32 | 'description' => static function () { 33 | return __( 'Indicates an R level avatar rating level.', 'wp-graphql' ); 34 | }, 35 | 'value' => 'R', 36 | ], 37 | 'X' => [ 38 | 'description' => static function () { 39 | return __( 'Indicates an X level avatar rating level.', 'wp-graphql' ); 40 | }, 41 | 'value' => 'X', 42 | ], 43 | ], 44 | ] 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Type/Enum/CommentNodeIdTypeEnum.php: -------------------------------------------------------------------------------- 1 | <?php 2 | namespace WPGraphQL\Type\Enum; 3 | 4 | /** 5 | * Class CommentNodeIdTypeEnum 6 | * 7 | * @package WPGraphQL\Type\Enum 8 | */ 9 | class CommentNodeIdTypeEnum { 10 | 11 | /** 12 | * Register the CommentNodeIdTypeEnum 13 | * 14 | * @return void 15 | */ 16 | public static function register_type() { 17 | register_graphql_enum_type( 18 | 'CommentNodeIdTypeEnum', 19 | [ 20 | 'description' => static function () { 21 | return __( 'Identifier types for retrieving a specific comment. Specifies which unique attribute is used to find a particular comment.', 'wp-graphql' ); 22 | }, 23 | 'values' => [ 24 | 'ID' => [ 25 | 'name' => 'ID', 26 | 'value' => 'global_id', 27 | 'description' => static function () { 28 | return __( 'Identify a resource by the (hashed) Global ID.', 'wp-graphql' ); 29 | }, 30 | ], 31 | 'DATABASE_ID' => [ 32 | 'name' => 'DATABASE_ID', 33 | 'value' => 'database_id', 34 | 'description' => static function () { 35 | return __( 'Identify a resource by the Database ID.', 'wp-graphql' ); 36 | }, 37 | ], 38 | ], 39 | ] 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Type/Enum/ContentTypeIdTypeEnum.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Type\Enum; 4 | 5 | class ContentTypeIdTypeEnum { 6 | 7 | /** 8 | * Register the ContentTypeIdTypeEnum Type to the Schema 9 | * 10 | * @return void 11 | */ 12 | public static function register_type() { 13 | register_graphql_enum_type( 14 | 'ContentTypeIdTypeEnum', 15 | [ 16 | 'description' => static function () { 17 | return __( 'Identifier types for retrieving a specific content type definition. Determines whether to look up content types by ID or name.', 'wp-graphql' ); 18 | }, 19 | 'values' => [ 20 | 'ID' => [ 21 | 'name' => 'ID', 22 | 'value' => 'id', 23 | 'description' => static function () { 24 | return __( 'The globally unique ID', 'wp-graphql' ); 25 | }, 26 | ], 27 | 'NAME' => [ 28 | 'name' => 'NAME', 29 | 'value' => 'name', 30 | 'description' => static function () { 31 | return __( 'The name of the content type.', 'wp-graphql' ); 32 | }, 33 | ], 34 | ], 35 | ] 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Type/Enum/MediaItemStatusEnum.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Type\Enum; 4 | 5 | use WPGraphQL\Type\WPEnumType; 6 | 7 | class MediaItemStatusEnum { 8 | 9 | /** 10 | * Register the MediaItemStatusEnum Type to the Schema 11 | * 12 | * @return void 13 | */ 14 | public static function register_type() { 15 | $values = []; 16 | 17 | $post_stati = [ 18 | 'inherit' => static function () { 19 | return __( 'Media that inherits its publication status from the parent content', 'wp-graphql' ); 20 | }, 21 | 'private' => static function () { 22 | return __( 'Media visible only to users with appropriate permissions', 'wp-graphql' ); 23 | }, 24 | 'trash' => static function () { 25 | return __( 'Media marked for deletion but still recoverable', 'wp-graphql' ); 26 | }, 27 | 'auto-draft' => static function () { 28 | return __( 'Automatically created media that has not been finalized', 'wp-graphql' ); 29 | }, 30 | ]; 31 | 32 | /** 33 | * Loop through the post_stati 34 | */ 35 | foreach ( $post_stati as $status => $description ) { 36 | $values[ WPEnumType::get_safe_name( $status ) ] = [ 37 | 'description' => $description, 38 | 'value' => $status, 39 | ]; 40 | } 41 | 42 | register_graphql_enum_type( 43 | 'MediaItemStatusEnum', 44 | [ 45 | 'description' => static function () { 46 | return __( 'Publication status for media items. Controls whether media is publicly accessible, private, or in another state.', 'wp-graphql' ); 47 | }, 48 | 'values' => $values, 49 | ] 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Type/Enum/MenuItemNodeIdTypeEnum.php: -------------------------------------------------------------------------------- 1 | <?php 2 | namespace WPGraphQL\Type\Enum; 3 | 4 | /** 5 | * Class MenuItemNodeIdTypeEnum 6 | * 7 | * @package WPGraphQL\Type\Enum 8 | */ 9 | class MenuItemNodeIdTypeEnum { 10 | 11 | /** 12 | * Register the MenuItemNodeIdTypeEnum 13 | * 14 | * @return void 15 | */ 16 | public static function register_type() { 17 | register_graphql_enum_type( 18 | 'MenuItemNodeIdTypeEnum', 19 | [ 20 | 'description' => static function () { 21 | return __( 'Identifier types for retrieving a specific menu item. Determines whether to look up menu items by global ID or database ID.', 'wp-graphql' ); 22 | }, 23 | 'values' => [ 24 | 'ID' => [ 25 | 'name' => 'ID', 26 | 'value' => 'global_id', 27 | 'description' => static function () { 28 | return __( 'Identify a resource by the (hashed) Global ID.', 'wp-graphql' ); 29 | }, 30 | ], 31 | 'DATABASE_ID' => [ 32 | 'name' => 'DATABASE_ID', 33 | 'value' => 'database_id', 34 | 'description' => static function () { 35 | return __( 'Identify a resource by the Database ID.', 'wp-graphql' ); 36 | }, 37 | ], 38 | ], 39 | ] 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Type/Enum/MenuLocationEnum.php: -------------------------------------------------------------------------------- 1 | <?php 2 | namespace WPGraphQL\Type\Enum; 3 | 4 | use WPGraphQL\Data\DataSource; 5 | use WPGraphQL\Type\WPEnumType; 6 | 7 | class MenuLocationEnum { 8 | 9 | /** 10 | * Register the MenuLocationEnum Type to the Schema 11 | * 12 | * @return void 13 | */ 14 | public static function register_type() { 15 | $values = []; 16 | 17 | $locations = DataSource::get_registered_nav_menu_locations(); 18 | 19 | if ( ! empty( $locations ) && is_array( $locations ) ) { 20 | foreach ( $locations as $location ) { 21 | $values[ WPEnumType::get_safe_name( $location ) ] = [ 22 | 'value' => $location, 23 | 'description' => static function () use ( $location ) { 24 | return sprintf( 25 | // translators: %s is the menu location name. 26 | __( 'Put the menu in the %s location', 'wp-graphql' ), 27 | $location 28 | ); 29 | }, 30 | ]; 31 | } 32 | } 33 | 34 | if ( empty( $values ) ) { 35 | $values['EMPTY'] = [ 36 | 'value' => 'Empty menu location', 37 | 'description' => static function () { 38 | return __( 'Empty menu location', 'wp-graphql' ); 39 | }, 40 | ]; 41 | } 42 | 43 | register_graphql_enum_type( 44 | 'MenuLocationEnum', 45 | [ 46 | 'description' => static function () { 47 | return __( 'Designated areas where navigation menus can be displayed. Represents the named regions in the interface where menus can be assigned.', 'wp-graphql' ); 48 | }, 49 | 'values' => $values, 50 | ] 51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Type/Enum/MimeTypeEnum.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Type\Enum; 4 | 5 | use WPGraphQL\Type\WPEnumType; 6 | 7 | class MimeTypeEnum { 8 | 9 | /** 10 | * Register the MimeTypeEnum Type to the Schema 11 | * 12 | * @return void 13 | */ 14 | public static function register_type() { 15 | $values = [ 16 | 'IMAGE_JPEG' => [ 17 | 'value' => 'image/jpeg', 18 | 'description' => static function () { 19 | return __( 'An image in the JPEG format', 'wp-graphql' ); 20 | }, 21 | ], 22 | ]; 23 | 24 | $allowed_mime_types = get_allowed_mime_types(); 25 | 26 | if ( ! empty( $allowed_mime_types ) ) { 27 | $values = []; 28 | foreach ( $allowed_mime_types as $mime_type ) { 29 | $values[ WPEnumType::get_safe_name( $mime_type ) ] = [ 30 | 'value' => $mime_type, 31 | 'description' => static function () use ( $mime_type ) { 32 | return sprintf( 33 | // translators: %s is the mime type. 34 | __( '%s mime type.', 'wp-graphql' ), 35 | $mime_type 36 | ); 37 | }, 38 | ]; 39 | } 40 | } 41 | 42 | register_graphql_enum_type( 43 | 'MimeTypeEnum', 44 | [ 45 | 'description' => static function () { 46 | return __( 'Media file type classification based on MIME standards. Used to identify and filter media items by their format and content type.', 'wp-graphql' ); 47 | }, 48 | 'values' => $values, 49 | ] 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Type/Enum/OrderEnum.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Type\Enum; 4 | 5 | class OrderEnum { 6 | 7 | /** 8 | * Register the OrderEnum Type to the Schema 9 | * 10 | * @return void 11 | */ 12 | public static function register_type() { 13 | register_graphql_enum_type( 14 | 'OrderEnum', 15 | [ 16 | 'description' => static function () { 17 | return __( 'Sort direction for ordered results. Determines whether items are returned in ascending or descending order.', 'wp-graphql' ); 18 | }, 19 | 'values' => [ 20 | 'ASC' => [ 21 | 'value' => 'ASC', 22 | 'description' => static function () { 23 | return __( 'Results ordered from lowest to highest values (i.e. A-Z, oldest-newest)', 'wp-graphql' ); 24 | }, 25 | ], 26 | 'DESC' => [ 27 | 'value' => 'DESC', 28 | 'description' => static function () { 29 | return __( 'Results ordered from highest to lowest values (i.e. Z-A, newest-oldest)', 'wp-graphql' ); 30 | }, 31 | ], 32 | ], 33 | 'defaultValue' => 'DESC', 34 | ] 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Type/Enum/PostObjectFieldFormatEnum.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Type\Enum; 4 | 5 | class PostObjectFieldFormatEnum { 6 | 7 | /** 8 | * Register the PostObjectFieldFormatEnum Type to the Schema 9 | * 10 | * @return void 11 | */ 12 | public static function register_type() { 13 | register_graphql_enum_type( 14 | 'PostObjectFieldFormatEnum', 15 | [ 16 | 'description' => static function () { 17 | return __( 'Content field rendering options. Determines whether content fields are returned as raw data or with applied formatting and transformations. Default is RENDERED.', 'wp-graphql' ); 18 | }, 19 | 'values' => [ 20 | 'RAW' => [ 21 | 'name' => 'RAW', 22 | 'description' => static function () { 23 | return __( 'Unprocessed content exactly as stored in the database, requires appropriate permissions.', 'wp-graphql' ); 24 | }, 25 | 'value' => 'raw', 26 | ], 27 | 'RENDERED' => [ 28 | 'name' => 'RENDERED', 29 | 'description' => static function () { 30 | return __( 'Content with all formatting and transformations applied, ready for display.', 'wp-graphql' ); 31 | }, 32 | 'value' => 'rendered', 33 | ], 34 | ], 35 | ] 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Type/Enum/PostObjectsConnectionDateColumnEnum.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Type\Enum; 4 | 5 | class PostObjectsConnectionDateColumnEnum { 6 | 7 | /** 8 | * Register the PostObjectsConnectionDateColumnEnum Type to the Schema 9 | * 10 | * @return void 11 | */ 12 | public static function register_type() { 13 | register_graphql_enum_type( 14 | 'PostObjectsConnectionDateColumnEnum', 15 | [ 16 | 'description' => static function () { 17 | return __( 'Date field selectors for content filtering. Specifies which date attribute (creation date, modification date) should be used for date-based queries.', 'wp-graphql' ); 18 | }, 19 | 'values' => [ 20 | 'DATE' => [ 21 | 'value' => 'post_date', 22 | 'description' => static function () { 23 | return __( 'The date the comment was created in local time.', 'wp-graphql' ); 24 | }, 25 | ], 26 | 'MODIFIED' => [ 27 | 'value' => 'post_modified', 28 | 'description' => static function () { 29 | return __( 'The most recent modification date of the comment.', 'wp-graphql' ); 30 | }, 31 | ], 32 | ], 33 | ] 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Type/Enum/RelationEnum.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Type\Enum; 4 | 5 | class RelationEnum { 6 | 7 | /** 8 | * Register the RelationEnum Type to the Schema 9 | * 10 | * @return void 11 | */ 12 | public static function register_type() { 13 | register_graphql_enum_type( 14 | 'RelationEnum', 15 | [ 16 | 'description' => static function () { 17 | return __( 'Logical operators for filter conditions. Determines whether multiple filtering criteria should be combined with AND (all must match) or OR (any can match).', 'wp-graphql' ); 18 | }, 19 | 'values' => [ 20 | 'AND' => [ 21 | 'name' => 'AND', 22 | 'value' => 'AND', 23 | 'description' => static function () { 24 | return __( 'All conditions must match (more restrictive filtering)', 'wp-graphql' ); 25 | }, 26 | ], 27 | 'OR' => [ 28 | 'name' => 'OR', 29 | 'value' => 'OR', 30 | 'description' => static function () { 31 | return __( 'Any condition can match (more inclusive filtering)', 'wp-graphql' ); 32 | }, 33 | ], 34 | ], 35 | ] 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Type/Enum/ScriptLoadingGroupLocationEnum.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Register the ScriptLoadingGroupLocationEnum Type to the Schema 4 | * 5 | * @package WPGraphQL\Type\Enum 6 | * @since 1.30.0 7 | */ 8 | 9 | namespace WPGraphQL\Type\Enum; 10 | 11 | /** 12 | * Class ScriptLoadingGroupLocationEnum 13 | */ 14 | class ScriptLoadingGroupLocationEnum { 15 | 16 | /** 17 | * Register the ScriptLoadingStrategy Enum Type to the Schema 18 | * 19 | * @return void 20 | */ 21 | public static function register_type() { 22 | register_graphql_enum_type( 23 | 'ScriptLoadingGroupLocationEnum', 24 | [ 25 | 'description' => static function () { 26 | return __( 'Script insertion positions in the document structure. Determines whether scripts are placed in the document head or before the closing body tag.', 'wp-graphql' ); 27 | }, 28 | 'values' => [ 29 | 'HEADER' => [ 30 | 'value' => 0, 31 | 'description' => static function () { 32 | return __( 'Early loading in document `<head>` tag. (executes before page content renders)', 'wp-graphql' ); 33 | }, 34 | ], 35 | 'FOOTER' => [ 36 | 'value' => 1, 37 | 'description' => static function () { 38 | return __( 'Delayed loading at end of document, right before the closing `<body>` tag. (allows content to render first)', 'wp-graphql' ); 39 | }, 40 | ], 41 | ], 42 | ] 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Type/Enum/ScriptLoadingStrategyEnum.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Register the ScriptLoadingStrategy Enum Type to the Schema 4 | * 5 | * @package WPGraphQL\Type\Enum 6 | * @since 1.19.0 7 | */ 8 | 9 | namespace WPGraphQL\Type\Enum; 10 | 11 | /** 12 | * Class ScriptLoadingStrategyEnum 13 | */ 14 | class ScriptLoadingStrategyEnum { 15 | 16 | /** 17 | * Register the ScriptLoadingStrategy Enum Type to the Schema 18 | * 19 | * @return void 20 | */ 21 | public static function register_type() { 22 | register_graphql_enum_type( 23 | 'ScriptLoadingStrategyEnum', 24 | [ 25 | 'description' => static function () { 26 | return __( 'Script loading optimization attributes. Controls browser behavior for script loading to improve page performance (async or defer).', 'wp-graphql' ); 27 | }, 28 | 'values' => [ 29 | 'ASYNC' => [ 30 | 'value' => 'async', 31 | 'description' => static function () { 32 | return __( 'Load script in parallel with page rendering, executing as soon as downloaded', 'wp-graphql' ); 33 | }, 34 | ], 35 | 'DEFER' => [ 36 | 'value' => 'defer', 37 | 'description' => static function () { 38 | return __( 'Download script in parallel but defer execution until page is fully parsed', 'wp-graphql' ); 39 | }, 40 | ], 41 | ], 42 | ] 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Type/Enum/TaxonomyEnum.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Type\Enum; 4 | 5 | use WPGraphQL\Type\WPEnumType; 6 | 7 | class TaxonomyEnum { 8 | 9 | /** 10 | * Register the TaxonomyEnum Type to the Schema 11 | * 12 | * @return void 13 | */ 14 | public static function register_type() { 15 | $allowed_taxonomies = \WPGraphQL::get_allowed_taxonomies( 'objects' ); 16 | 17 | $values = []; 18 | 19 | /** 20 | * Loop through the taxonomies and create an array 21 | * of values for use in the enum type. 22 | */ 23 | 24 | foreach ( $allowed_taxonomies as $tax_object ) { 25 | if ( ! isset( $values[ WPEnumType::get_safe_name( $tax_object->graphql_single_name ) ] ) ) { 26 | $values[ WPEnumType::get_safe_name( $tax_object->graphql_single_name ) ] = [ 27 | 'value' => $tax_object->name, 28 | 'description' => static function () use ( $tax_object ) { 29 | return sprintf( 30 | // translators: %s is the taxonomy name. 31 | __( 'Taxonomy enum %s', 'wp-graphql' ), 32 | $tax_object->name 33 | ); 34 | }, 35 | ]; 36 | } 37 | } 38 | 39 | register_graphql_enum_type( 40 | 'TaxonomyEnum', 41 | [ 42 | 'description' => static function () { 43 | return __( 'Available classification systems for organizing content. Identifies the different taxonomy types that can be used for content categorization.', 'wp-graphql' ); 44 | }, 45 | 'values' => $values, 46 | ] 47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Type/Enum/TaxonomyIdTypeEnum.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Type\Enum; 4 | 5 | class TaxonomyIdTypeEnum { 6 | 7 | /** 8 | * Register the TaxonomyIdTypeEnum Type to the Schema 9 | * 10 | * @return void 11 | */ 12 | public static function register_type() { 13 | register_graphql_enum_type( 14 | 'TaxonomyIdTypeEnum', 15 | [ 16 | 'description' => static function () { 17 | return __( 'Identifier types for retrieving a taxonomy definition. Determines whether to look up taxonomies by ID or name.', 'wp-graphql' ); 18 | }, 19 | 'values' => [ 20 | 'ID' => [ 21 | 'name' => 'ID', 22 | 'value' => 'id', 23 | 'description' => static function () { 24 | return __( 'The globally unique ID', 'wp-graphql' ); 25 | }, 26 | ], 27 | 'NAME' => [ 28 | 'name' => 'NAME', 29 | 'value' => 'name', 30 | 'description' => static function () { 31 | return __( 'The name of the taxonomy', 'wp-graphql' ); 32 | }, 33 | ], 34 | ], 35 | ] 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Type/Input/DateInput.php: -------------------------------------------------------------------------------- 1 | <?php 2 | namespace WPGraphQL\Type\Input; 3 | 4 | class DateInput { 5 | 6 | /** 7 | * Register the DateInput Input 8 | * 9 | * @return void 10 | */ 11 | public static function register_type() { 12 | register_graphql_input_type( 13 | 'DateInput', 14 | [ 15 | 'description' => static function () { 16 | return __( 'Date values', 'wp-graphql' ); 17 | }, 18 | 'fields' => static function () { 19 | return [ 20 | 'year' => [ 21 | 'type' => 'Int', 22 | 'description' => static function () { 23 | return __( '4 digit year (e.g. 2017)', 'wp-graphql' ); 24 | }, 25 | ], 26 | 'month' => [ 27 | 'type' => 'Int', 28 | 'description' => static function () { 29 | return __( 'Month number (from 1 to 12)', 'wp-graphql' ); 30 | }, 31 | ], 32 | 'day' => [ 33 | 'type' => 'Int', 34 | 'description' => static function () { 35 | return __( 'Day of the month (from 1 to 31)', 'wp-graphql' ); 36 | }, 37 | ], 38 | ]; 39 | }, 40 | ] 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Type/Input/PostObjectsConnectionOrderbyInput.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Type\Input; 4 | 5 | class PostObjectsConnectionOrderbyInput { 6 | 7 | /** 8 | * Register the PostObjectsConnectionOrderbyInput Input 9 | * 10 | * @return void 11 | */ 12 | public static function register_type() { 13 | register_graphql_input_type( 14 | 'PostObjectsConnectionOrderbyInput', 15 | [ 16 | 'description' => static function () { 17 | return __( 'Options for ordering the connection', 'wp-graphql' ); 18 | }, 19 | 'fields' => static function () { 20 | return [ 21 | 'field' => [ 22 | 'type' => [ 23 | 'non_null' => 'PostObjectsConnectionOrderbyEnum', 24 | ], 25 | 'description' => static function () { 26 | return __( 'The field to order the connection by', 'wp-graphql' ); 27 | }, 28 | ], 29 | 'order' => [ 30 | 'type' => [ 31 | 'non_null' => 'OrderEnum', 32 | ], 33 | 'description' => static function () { 34 | return __( 'Possible directions in which to order a list of items', 'wp-graphql' ); 35 | }, 36 | ], 37 | ]; 38 | }, 39 | ] 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Type/Input/UsersConnectionOrderbyInput.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Type\Input; 4 | 5 | class UsersConnectionOrderbyInput { 6 | 7 | /** 8 | * Register the UsersConnectionOrderbyInput Input 9 | * 10 | * @return void 11 | */ 12 | public static function register_type() { 13 | register_graphql_input_type( 14 | 'UsersConnectionOrderbyInput', 15 | [ 16 | 'description' => static function () { 17 | return __( 'Options for ordering the connection', 'wp-graphql' ); 18 | }, 19 | 'fields' => static function () { 20 | return [ 21 | 'field' => [ 22 | 'description' => static function () { 23 | return __( 'The field name used to sort the results.', 'wp-graphql' ); 24 | }, 25 | 'type' => [ 26 | 'non_null' => 'UsersConnectionOrderbyEnum', 27 | ], 28 | ], 29 | 'order' => [ 30 | 'description' => static function () { 31 | return __( 'The cardinality of the order of the connection', 'wp-graphql' ); 32 | }, 33 | 'type' => 'OrderEnum', 34 | ], 35 | ]; 36 | }, 37 | ] 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Type/InterfaceType/Connection.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Type\InterfaceType; 4 | 5 | use WPGraphQL\Registry\TypeRegistry; 6 | 7 | class Connection { 8 | /** 9 | * Register the Connection Interface 10 | * 11 | * @param \WPGraphQL\Registry\TypeRegistry $type_registry 12 | * 13 | * @throws \Exception 14 | */ 15 | public static function register_type( TypeRegistry $type_registry ): void { 16 | register_graphql_interface_type( 17 | 'Connection', 18 | [ 19 | 'description' => static function () { 20 | return __( 'A paginated relationship between objects. Supports cursor-based pagination with edges containing relationship metadata and nodes containing the related objects.', 'wp-graphql' ); 21 | }, 22 | 'fields' => static function () { 23 | return [ 24 | 'pageInfo' => [ 25 | 'type' => [ 'non_null' => 'PageInfo' ], 26 | 'description' => static function () { 27 | return __( 'Information about pagination in a connection.', 'wp-graphql' ); 28 | }, 29 | ], 30 | 'edges' => [ 31 | 'type' => [ 'non_null' => [ 'list_of' => [ 'non_null' => 'Edge' ] ] ], 32 | 'description' => static function () { 33 | return __( 'A list of edges (relational context) between connected nodes', 'wp-graphql' ); 34 | }, 35 | ], 36 | 'nodes' => [ 37 | 'type' => [ 'non_null' => [ 'list_of' => [ 'non_null' => 'Node' ] ] ], 38 | 'description' => static function () { 39 | return __( 'A list of connected nodes', 'wp-graphql' ); 40 | }, 41 | ], 42 | ]; 43 | }, 44 | ] 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Type/InterfaceType/DatabaseIdentifier.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Type\InterfaceType; 4 | 5 | /** 6 | * Class DatabaseIdentifier 7 | * 8 | * @package WPGraphQL\Type\InterfaceType 9 | */ 10 | class DatabaseIdentifier { 11 | 12 | /** 13 | * Register the DatabaseIdentifier Interface. 14 | * 15 | * @return void 16 | */ 17 | public static function register_type() { 18 | register_graphql_interface_type( 19 | 'DatabaseIdentifier', 20 | [ 21 | 'description' => static function () { 22 | return __( 'An object that has a unique numeric identifier in the database. Provides consistent access to the database ID across different object types.', 'wp-graphql' ); 23 | }, 24 | 'fields' => static function () { 25 | return [ 26 | 'databaseId' => [ 27 | 'type' => [ 'non_null' => 'Int' ], 28 | 'description' => static function () { 29 | return __( 'The unique identifier stored in the database', 'wp-graphql' ); 30 | }, 31 | ], 32 | ]; 33 | }, 34 | ] 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Type/InterfaceType/Edge.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Type\InterfaceType; 4 | 5 | use WPGraphQL\Registry\TypeRegistry; 6 | 7 | class Edge { 8 | /** 9 | * Register the Connection Interface 10 | * 11 | * @param \WPGraphQL\Registry\TypeRegistry $type_registry 12 | * 13 | * @throws \Exception 14 | */ 15 | public static function register_type( TypeRegistry $type_registry ): void { 16 | register_graphql_interface_type( 17 | 'Edge', 18 | [ 19 | 'description' => static function () { 20 | return __( 'Represents a connection between two objects. Contains both the related object (node) and metadata about the relationship (cursor).', 'wp-graphql' ); 21 | }, 22 | 'fields' => static function () { 23 | return [ 24 | 'cursor' => [ 25 | 'type' => 'String', 26 | 'description' => static function () { 27 | return __( 'Opaque reference to the nodes position in the connection. Value can be used with pagination args.', 'wp-graphql' ); 28 | }, 29 | ], 30 | 'node' => [ 31 | 'type' => [ 'non_null' => 'Node' ], 32 | 'description' => static function () { 33 | return __( 'The connected node', 'wp-graphql' ); 34 | }, 35 | ], 36 | ]; 37 | }, 38 | ] 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Type/InterfaceType/HierarchicalContentNode.php: -------------------------------------------------------------------------------- 1 | <?php 2 | namespace WPGraphQL\Type\InterfaceType; 3 | 4 | use WPGraphQL\Registry\TypeRegistry; 5 | 6 | /** 7 | * Class HierarchicalContentNode 8 | * 9 | * @package WPGraphQL\Type\InterfaceType 10 | */ 11 | class HierarchicalContentNode { 12 | 13 | /** 14 | * Register the HierarchicalContentNode Interface Type 15 | * 16 | * @param \WPGraphQL\Registry\TypeRegistry $type_registry 17 | * 18 | * @throws \Exception 19 | */ 20 | public static function register_type( TypeRegistry $type_registry ): void { 21 | register_graphql_interface_type( 22 | 'HierarchicalContentNode', 23 | [ 24 | 'description' => static function () { 25 | return __( 'Content that can be organized in a parent-child structure. Provides fields for navigating up and down the hierarchy and maintaining structured relationships.', 'wp-graphql' ); 26 | }, 27 | 'interfaces' => [ 28 | 'Node', 29 | 'ContentNode', 30 | 'DatabaseIdentifier', 31 | 'HierarchicalNode', 32 | ], 33 | 'fields' => static function () { 34 | return [ 35 | 'parentId' => [ 36 | 'type' => 'ID', 37 | 'description' => static function () { 38 | return __( 'The globally unique identifier of the parent node.', 'wp-graphql' ); 39 | }, 40 | ], 41 | 'parentDatabaseId' => [ 42 | 'type' => 'Int', 43 | 'description' => static function () { 44 | return __( 'Database id of the parent node', 'wp-graphql' ); 45 | }, 46 | ], 47 | ]; 48 | }, 49 | ] 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Type/InterfaceType/HierarchicalNode.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Type\InterfaceType; 4 | 5 | use WPGraphQL\Registry\TypeRegistry; 6 | 7 | /** 8 | * Class HierarchicalNode 9 | * 10 | * @package WPGraphQL\Type\InterfaceType 11 | */ 12 | class HierarchicalNode { 13 | 14 | /** 15 | * Register the HierarchicalNode Interface Type 16 | * 17 | * @param \WPGraphQL\Registry\TypeRegistry $type_registry 18 | * 19 | * @throws \Exception 20 | */ 21 | public static function register_type( TypeRegistry $type_registry ): void { 22 | register_graphql_interface_type( 23 | 'HierarchicalNode', 24 | [ 25 | 'description' => static function () { 26 | return __( 'Content that can exist in a parent-child structure. Provides fields for navigating up (parent) and down (children) through the hierarchy.', 'wp-graphql' ); 27 | }, 28 | 'interfaces' => [ 29 | 'Node', 30 | 'DatabaseIdentifier', 31 | ], 32 | 'fields' => static function () { 33 | return [ 34 | 'parentId' => [ 35 | 'type' => 'ID', 36 | 'description' => static function () { 37 | return __( 'The globally unique identifier of the parent node.', 'wp-graphql' ); 38 | }, 39 | ], 40 | 'parentDatabaseId' => [ 41 | 'type' => 'Int', 42 | 'description' => static function () { 43 | return __( 'Database id of the parent node', 'wp-graphql' ); 44 | }, 45 | ], 46 | ]; 47 | }, 48 | ] 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Type/InterfaceType/HierarchicalTermNode.php: -------------------------------------------------------------------------------- 1 | <?php 2 | namespace WPGraphQL\Type\InterfaceType; 3 | 4 | use WPGraphQL\Registry\TypeRegistry; 5 | 6 | /** 7 | * Class HierarchicalTermNode 8 | * 9 | * @package WPGraphQL\Type\InterfaceType 10 | */ 11 | class HierarchicalTermNode { 12 | 13 | /** 14 | * Register the HierarchicalTermNode Interface Type 15 | * 16 | * @param \WPGraphQL\Registry\TypeRegistry $type_registry 17 | * 18 | * @throws \Exception 19 | */ 20 | public static function register_type( TypeRegistry $type_registry ): void { 21 | register_graphql_interface_type( 22 | 'HierarchicalTermNode', 23 | [ 24 | 'description' => static function () { 25 | return __( 'Term node with hierarchical (parent/child) relationships', 'wp-graphql' ); 26 | }, 27 | 'interfaces' => [ 28 | 'Node', 29 | 'TermNode', 30 | 'DatabaseIdentifier', 31 | 'HierarchicalNode', 32 | ], 33 | 'fields' => static function () { 34 | return [ 35 | 'parentId' => [ 36 | 'type' => 'ID', 37 | 'description' => static function () { 38 | return __( 'The globally unique identifier of the parent node.', 'wp-graphql' ); 39 | }, 40 | ], 41 | 'parentDatabaseId' => [ 42 | 'type' => 'Int', 43 | 'description' => static function () { 44 | return __( 'Database id of the parent node', 'wp-graphql' ); 45 | }, 46 | ], 47 | ]; 48 | }, 49 | ] 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Type/InterfaceType/Node.php: -------------------------------------------------------------------------------- 1 | <?php 2 | namespace WPGraphQL\Type\InterfaceType; 3 | 4 | use WPGraphQL\Data\DataSource; 5 | 6 | class Node { 7 | 8 | /** 9 | * Register the Node interface 10 | * 11 | * @return void 12 | */ 13 | public static function register_type() { 14 | register_graphql_interface_type( 15 | 'Node', 16 | [ 17 | 'description' => static function () { 18 | return __( 'An object with a globally unique identifier. All objects that can be identified by a unique ID implement this interface.', 'wp-graphql' ); 19 | }, 20 | 'fields' => static function () { 21 | return [ 22 | 'id' => [ 23 | 'type' => [ 'non_null' => 'ID' ], 24 | 'description' => static function () { 25 | return __( 'The globally unique ID for the object', 'wp-graphql' ); 26 | }, 27 | ], 28 | ]; 29 | }, 30 | 'resolveType' => static function ( $node ) { 31 | return DataSource::resolve_node_type( $node ); 32 | }, 33 | ] 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Type/InterfaceType/NodeWithAuthor.php: -------------------------------------------------------------------------------- 1 | <?php 2 | namespace WPGraphQL\Type\InterfaceType; 3 | 4 | use WPGraphQL\Registry\TypeRegistry; 5 | 6 | class NodeWithAuthor { 7 | /** 8 | * Registers the NodeWithAuthor Type to the Schema 9 | * 10 | * @param \WPGraphQL\Registry\TypeRegistry $type_registry 11 | * 12 | * @return void 13 | */ 14 | public static function register_type( TypeRegistry $type_registry ) { 15 | register_graphql_interface_type( 16 | 'NodeWithAuthor', 17 | [ 18 | 'interfaces' => [ 'Node' ], 19 | 'description' => static function () { 20 | return __( 'Content that can be attributed to a specific user. Provides fields for accessing the author\'s information and establishing content ownership.', 'wp-graphql' ); 21 | }, 22 | 'fields' => static function () { 23 | return [ 24 | 'authorId' => [ 25 | 'type' => 'ID', 26 | 'description' => static function () { 27 | return __( 'The globally unique identifier of the author of the node', 'wp-graphql' ); 28 | }, 29 | ], 30 | 'authorDatabaseId' => [ 31 | 'type' => 'Int', 32 | 'description' => static function () { 33 | return __( 'The database identifier of the author of the node', 'wp-graphql' ); 34 | }, 35 | ], 36 | ]; 37 | }, 38 | ] 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Type/InterfaceType/NodeWithComments.php: -------------------------------------------------------------------------------- 1 | <?php 2 | namespace WPGraphQL\Type\InterfaceType; 3 | 4 | use WPGraphQL\Registry\TypeRegistry; 5 | 6 | class NodeWithComments { 7 | /** 8 | * Registers the NodeWithComments Type to the Schema 9 | * 10 | * @param \WPGraphQL\Registry\TypeRegistry $type_registry 11 | * 12 | * @return void 13 | */ 14 | public static function register_type( TypeRegistry $type_registry ) { 15 | register_graphql_interface_type( 16 | 'NodeWithComments', 17 | [ 18 | 'interfaces' => [ 'Node' ], 19 | 'description' => static function () { 20 | return __( 'Content that can receive and display user-submitted comments. Provides fields for accessing comment counts and managing comment status.', 'wp-graphql' ); 21 | }, 22 | 'fields' => static function () { 23 | return [ 24 | 'commentCount' => [ 25 | 'type' => 'Int', 26 | 'description' => static function () { 27 | return __( 'The number of comments. Even though WPGraphQL denotes this field as an integer, in WordPress this field should be saved as a numeric string for compatibility.', 'wp-graphql' ); 28 | }, 29 | ], 30 | 'commentStatus' => [ 31 | 'type' => 'String', 32 | 'description' => static function () { 33 | return __( 'Whether the comments are open or closed for this particular post.', 'wp-graphql' ); 34 | }, 35 | ], 36 | ]; 37 | }, 38 | ] 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Type/InterfaceType/NodeWithPageAttributes.php: -------------------------------------------------------------------------------- 1 | <?php 2 | namespace WPGraphQL\Type\InterfaceType; 3 | 4 | use WPGraphQL\Registry\TypeRegistry; 5 | 6 | class NodeWithPageAttributes { 7 | 8 | /** 9 | * Registers the NodeWithPageAttributes Type to the Schema 10 | * 11 | * @param \WPGraphQL\Registry\TypeRegistry $type_registry 12 | * 13 | * @return void 14 | */ 15 | public static function register_type( TypeRegistry $type_registry ) { 16 | register_graphql_interface_type( 17 | 'NodeWithPageAttributes', 18 | [ 19 | 'interfaces' => [ 'Node' ], 20 | 'description' => static function () { 21 | return __( 'Content that supports ordering metadata. Includes a menu order field which can be used for custom sorting in navigation menus and other ordered collections.', 'wp-graphql' ); 22 | }, 23 | 'fields' => static function () { 24 | return [ 25 | 'menuOrder' => [ 26 | 'type' => 'Int', 27 | 'description' => static function () { 28 | return __( 'A field used for ordering posts. This is typically used with nav menu items or for special ordering of hierarchical content types.', 'wp-graphql' ); 29 | }, 30 | ], 31 | ]; 32 | }, 33 | ] 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Type/InterfaceType/NodeWithRevisions.php: -------------------------------------------------------------------------------- 1 | <?php 2 | namespace WPGraphQL\Type\InterfaceType; 3 | 4 | use WPGraphQL\Registry\TypeRegistry; 5 | 6 | class NodeWithRevisions { 7 | 8 | /** 9 | * Registers the NodeWithRevisions Type to the Schema 10 | * 11 | * @param \WPGraphQL\Registry\TypeRegistry $type_registry 12 | * 13 | * @return void 14 | */ 15 | public static function register_type( TypeRegistry $type_registry ) { 16 | register_graphql_interface_type( 17 | 'NodeWithRevisions', 18 | [ 19 | 'interfaces' => [ 'Node' ], 20 | 'description' => static function () { 21 | return __( 'Content that maintains a history of changes. Provides access to previous versions of the content and the ability to restore earlier revisions.', 'wp-graphql' ); 22 | }, 23 | 'fields' => static function () { 24 | return [ 25 | 'isRevision' => [ 26 | 'type' => 'Boolean', 27 | 'description' => static function () { 28 | return __( 'True if the node is a revision of another node', 'wp-graphql' ); 29 | }, 30 | ], 31 | ]; 32 | }, 33 | ] 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Type/InterfaceType/NodeWithTemplate.php: -------------------------------------------------------------------------------- 1 | <?php 2 | namespace WPGraphQL\Type\InterfaceType; 3 | 4 | use WPGraphQL\Registry\TypeRegistry; 5 | 6 | class NodeWithTemplate { 7 | 8 | /** 9 | * Registers the NodeWithTemplate Type to the Schema 10 | * 11 | * @param \WPGraphQL\Registry\TypeRegistry $type_registry 12 | * 13 | * @return void 14 | */ 15 | public static function register_type( TypeRegistry $type_registry ) { 16 | register_graphql_interface_type( 17 | 'NodeWithTemplate', 18 | [ 19 | 'description' => static function () { 20 | return __( 'Content that provides template metadata. The template can help inform how the content is might be structured, styled, and presented to the user.', 'wp-graphql' ); 21 | }, 22 | 'interfaces' => [ 'Node' ], 23 | 'fields' => static function () { 24 | return [ 25 | 'template' => [ 26 | 'description' => static function () { 27 | return __( 'The template assigned to the node', 'wp-graphql' ); 28 | }, 29 | 'type' => 'ContentTemplate', 30 | ], 31 | ]; 32 | }, 33 | ] 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Type/InterfaceType/NodeWithTrackbacks.php: -------------------------------------------------------------------------------- 1 | <?php 2 | namespace WPGraphQL\Type\InterfaceType; 3 | 4 | use WPGraphQL\Registry\TypeRegistry; 5 | 6 | class NodeWithTrackbacks { 7 | 8 | /** 9 | * Registers the NodeWithTrackbacks Type to the Schema 10 | * 11 | * @param \WPGraphQL\Registry\TypeRegistry $type_registry 12 | * 13 | * @return void 14 | */ 15 | public static function register_type( TypeRegistry $type_registry ) { 16 | register_graphql_interface_type( 17 | 'NodeWithTrackbacks', 18 | [ 19 | 'interfaces' => [ 'Node' ], 20 | 'description' => static function () { 21 | return __( 'Content that supports cross-site notifications when linked to by other sites. Includes fields for pingback status and linked URLs.', 'wp-graphql' ); 22 | }, 23 | 'fields' => static function () { 24 | return [ 25 | 'toPing' => [ 26 | 'type' => [ 'list_of' => 'String' ], 27 | 'description' => static function () { 28 | return __( 'URLs queued to be pinged.', 'wp-graphql' ); 29 | }, 30 | ], 31 | 'pinged' => [ 32 | 'type' => [ 'list_of' => 'String' ], 33 | 'description' => static function () { 34 | return __( 'URLs that have been pinged.', 'wp-graphql' ); 35 | }, 36 | ], 37 | 'pingStatus' => [ 38 | 'type' => 'String', 39 | 'description' => static function () { 40 | return __( 'Whether the pings are open or closed for this particular post.', 'wp-graphql' ); 41 | }, 42 | ], 43 | ]; 44 | }, 45 | ] 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Type/InterfaceType/OneToOneConnection.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Type\InterfaceType; 4 | 5 | use WPGraphQL\Registry\TypeRegistry; 6 | 7 | class OneToOneConnection { 8 | /** 9 | * Register the Connection Interface 10 | * 11 | * @param \WPGraphQL\Registry\TypeRegistry $type_registry 12 | * 13 | * @throws \Exception 14 | */ 15 | public static function register_type( TypeRegistry $type_registry ): void { 16 | register_graphql_interface_type( 17 | 'OneToOneConnection', 18 | [ 19 | 'description' => static function () { 20 | return __( 'A direct one-to-one relationship between objects. Unlike plural connections, this represents a single related object rather than a collection.', 'wp-graphql' ); 21 | }, 22 | 'interfaces' => [ 'Edge' ], 23 | 'fields' => static function () { 24 | return [ 25 | 'node' => [ 26 | 'type' => [ 'non_null' => 'Node' ], 27 | 'description' => static function () { 28 | return __( 'The connected node', 'wp-graphql' ); 29 | }, 30 | ], 31 | ]; 32 | }, 33 | ] 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Type/ObjectType/PostObject.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Type\ObjectType; 4 | 5 | use WPGraphQL\Registry\TypeRegistry; 6 | use WP_Post_Type; 7 | 8 | /** 9 | * WPObject - PostObject 10 | * 11 | * @package WPGraphQL\Type 12 | * @deprecated 1.12.0 13 | */ 14 | class PostObject { 15 | 16 | /** 17 | * Registers a post_type WPObject type to the schema. 18 | * 19 | * @param \WP_Post_Type $post_type_object Post type. 20 | * @param \WPGraphQL\Registry\TypeRegistry $type_registry The Type Registry 21 | * 22 | * @return void 23 | * @throws \Exception 24 | * @deprecated 1.12.0 25 | */ 26 | public static function register_post_object_types( WP_Post_Type $post_type_object, TypeRegistry $type_registry ) { 27 | _deprecated_function( __FUNCTION__, '1.12.0', esc_attr( \WPGraphQL\Registry\Utils\PostObject::class ) . '::register_types()' ); 28 | 29 | \WPGraphQL\Registry\Utils\PostObject::register_types( $post_type_object ); 30 | } 31 | 32 | /** 33 | * Registers common post type fields on schema type corresponding to provided post type object. 34 | * 35 | * @param \WP_Post_Type $post_type_object Post type. 36 | * @param \WPGraphQL\Registry\TypeRegistry $type_registry The Type Registry 37 | * 38 | * @deprecated 1.12.0 39 | * 40 | * @return array<string,array<string,mixed>> 41 | */ 42 | public static function get_fields( $post_type_object, $type_registry ) { 43 | _deprecated_function( __FUNCTION__, '1.12.0', esc_attr( \WPGraphQL\Registry\Utils\PostObject::class ) . '::get_fields()' ); 44 | 45 | return \WPGraphQL\Registry\Utils\PostObject::get_fields( $post_type_object ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Type/ObjectType/RootMutation.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Type\ObjectType; 4 | 5 | class RootMutation { 6 | 7 | /** 8 | * Register RootMutation type 9 | * 10 | * @return void 11 | */ 12 | public static function register_type() { 13 | register_graphql_object_type( 14 | 'RootMutation', 15 | [ 16 | 'description' => static function () { 17 | return __( 'The root mutation', 'wp-graphql' ); 18 | }, 19 | 'fields' => static function () { 20 | return [ 21 | 'increaseCount' => [ 22 | 'type' => 'Int', 23 | 'description' => static function () { 24 | return __( 'Increase the count.', 'wp-graphql' ); 25 | }, 26 | 'args' => [ 27 | 'count' => [ 28 | 'type' => 'Int', 29 | 'description' => static function () { 30 | return __( 'The count to increase', 'wp-graphql' ); 31 | }, 32 | ], 33 | ], 34 | 'resolve' => static function ( $root, $args ) { 35 | return isset( $args['count'] ) ? absint( $args['count'] ) + 1 : null; 36 | }, 37 | ], 38 | ]; 39 | }, 40 | ] 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Type/ObjectType/TermObject.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL\Type\ObjectType; 4 | 5 | use WP_Taxonomy; 6 | 7 | /** 8 | * Class TermObject 9 | * 10 | * @package WPGraphQL\Type\Object 11 | * @deprecated 1.12.0 12 | */ 13 | class TermObject { 14 | 15 | /** 16 | * Register the Type for each kind of Taxonomy 17 | * 18 | * @param \WP_Taxonomy $tax_object The taxonomy being registered 19 | * 20 | * @return void 21 | * @throws \Exception 22 | * @deprecated 1.12.0 23 | */ 24 | public static function register_taxonomy_object_type( WP_Taxonomy $tax_object ) { 25 | _deprecated_function( __FUNCTION__, '1.12.0', esc_attr( \WPGraphQL\Registry\Utils\TermObject::class ) . '::register_types()' ); 26 | 27 | \WPGraphQL\Registry\Utils\TermObject::register_types( $tax_object ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Type/README.md: -------------------------------------------------------------------------------- 1 | # Type 2 | 3 | This directory contains type definitions. Each type is registered into the TypeRegistry for 4 | use throughout the Schema. 5 | 6 | -------------------------------------------------------------------------------- /src/Types.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL; 4 | 5 | use WPGraphQL\Utils\Utils; 6 | 7 | /** 8 | * This class was used to access Type definitions pre v0.4.0, but is no longer used. 9 | * See upgrade guide vor v0.4.0 (https://github.com/wp-graphql/wp-graphql/releases/tag/v0.4.0) for 10 | * information on updating to use non-static TypeRegistry methods to get_type(), etc. 11 | * 12 | * @deprecated since v0.6.0. Old static methods can now be done by accessing the 13 | * TypeRegistry class from within the `graphql_register_types` hook 14 | */ 15 | class Types { 16 | 17 | /** 18 | * @deprecated since v0.6.0. Use Utils:map_input instead 19 | * 20 | * @param mixed[] $args The raw query args from the GraphQL query. 21 | * @param mixed[] $map The mapping of where each of the args should go. 22 | * 23 | * @return array<string,mixed> 24 | */ 25 | public static function map_input( $args, $map ) { 26 | _deprecated_function( __METHOD__, '0.6.0', 'WPGraphQL\Utils\Utils::map_input()' ); 27 | return Utils::map_input( $args, $map ); 28 | } 29 | 30 | /** 31 | * @deprecated since v0.6.0 use Utils::prepare_date_response(); instead 32 | * @param string $date_gmt GMT publication time. 33 | * @param string|null $date Optional. Local publication time. Default null. 34 | * @return string|null ISO8601/RFC3339 formatted datetime. 35 | */ 36 | public static function prepare_date_response( $date_gmt, $date = null ) { 37 | _deprecated_function( __METHOD__, '0.6.0', 'WPGraphQL\Utils\Utils::prepare_date_response()' ); 38 | return Utils::prepare_date_response( $date_gmt, $date ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/WPSchema.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace WPGraphQL; 4 | 5 | use GraphQL\Type\Schema; 6 | use GraphQL\Type\SchemaConfig; 7 | use WPGraphQL\Registry\TypeRegistry; 8 | 9 | /** 10 | * Class WPSchema 11 | * 12 | * Extends the Schema to make some properties accessible via hooks/filters 13 | * 14 | * @package WPGraphQL 15 | */ 16 | class WPSchema extends Schema { 17 | /** 18 | * {@inheritDoc} 19 | * 20 | * @var \GraphQL\Type\SchemaConfig 21 | */ 22 | public $config; 23 | 24 | /** 25 | * Holds the $filterable_config which allows WordPress access to modifying the 26 | * $config that gets passed down to the Executable Schema 27 | * 28 | * @var \GraphQL\Type\SchemaConfig 29 | * @since 0.0.9 30 | */ 31 | public $filterable_config; 32 | 33 | /** 34 | * WPSchema constructor. 35 | * 36 | * @param \GraphQL\Type\SchemaConfig $config The config for the Schema. 37 | * @param \WPGraphQL\Registry\TypeRegistry $type_registry 38 | * 39 | * @since 0.0.9 40 | */ 41 | public function __construct( SchemaConfig $config, TypeRegistry $type_registry ) { 42 | $this->config = $config; 43 | 44 | /** 45 | * Set the $filterable_config as the $config that was passed to the WPSchema when instantiated 46 | * 47 | * @param \GraphQL\Type\SchemaConfig $config The config for the Schema. 48 | * @param \WPGraphQL\Registry\TypeRegistry $type_registry The WPGraphQL type registry. 49 | * 50 | * @since 0.0.9 51 | */ 52 | $this->filterable_config = apply_filters( 'graphql_schema_config', $config, $type_registry ); 53 | parent::__construct( $this->filterable_config ); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/assets/README.md: -------------------------------------------------------------------------------- 1 | # Assets 2 | 3 | Directory that contains assets intended for use within the plugin. 4 | -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | acceptance.suite.yml 2 | functional.suite.yml 3 | wpunit.suite.yml 4 | unit.suite.yml 5 | -------------------------------------------------------------------------------- /tests/_data/.gitignore: -------------------------------------------------------------------------------- 1 | dump.sql -------------------------------------------------------------------------------- /tests/_data/classes/WP_Query_Incompatible.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * An Incompatible WP_Query clone for testing 4 | * 5 | * @package Test\WPGraphQL 6 | */ 7 | 8 | /** 9 | * Class WP_Query_Incompatible 10 | */ 11 | class WP_Query_Incompatible {} 12 | -------------------------------------------------------------------------------- /tests/_data/config.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Disable autoloading while running tests, as the test 4 | * suite already bootstraps the autoloader and creates 5 | * fatal errors when the autoloader is loaded twice 6 | */ 7 | define( 'GRAPHQL_DEBUG', true ); 8 | define( 'WPGRAPHQL_AUTOLOAD', false ); 9 | define( 'WP_AUTO_UPDATE_CORE', false ); 10 | define( 'AUTOMATIC_UPDATER_DISABLED', true ); 11 | -------------------------------------------------------------------------------- /tests/_data/images/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !test*.* 3 | 4 | -------------------------------------------------------------------------------- /tests/_data/images/test-2000x1000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/tests/_data/images/test-2000x1000.png -------------------------------------------------------------------------------- /tests/_data/images/test-medium.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/tests/_data/images/test-medium.png -------------------------------------------------------------------------------- /tests/_data/images/test-mgc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/tests/_data/images/test-mgc.gif -------------------------------------------------------------------------------- /tests/_data/images/test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/tests/_data/images/test.png -------------------------------------------------------------------------------- /tests/_data/media/test.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-graphql/wp-graphql/dc670cf5be1fce3e7b80cdc39cae7fc84866b079/tests/_data/media/test.pdf -------------------------------------------------------------------------------- /tests/_data/plugins/plugin-incompatible-version.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Plugin Name: Incompatible Version 4 | * Version: 1.0.0 5 | * Description: A plugin with headers. 6 | * Requires WPGraphQL: 99.2.1 7 | * WPGraphQL Tested Up To: 1000.0.0 8 | */ 9 | 10 | // Exit if accessed directly. 11 | if ( ! defined( 'ABSPATH' ) ) { 12 | exit; 13 | } 14 | -------------------------------------------------------------------------------- /tests/_data/plugins/plugin-with-headers.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Plugin Name: Test Plugin With Headers 4 | * Version: 1.0.0 5 | * Description: A plugin with headers. 6 | * Requires WPGraphQL: 1.0.0 7 | * WPGraphQL Tested Up To: 1.0.0 8 | */ 9 | 10 | // Exit if accessed directly. 11 | if ( ! defined( 'ABSPATH' ) ) { 12 | exit; 13 | } 14 | -------------------------------------------------------------------------------- /tests/_data/plugins/plugin-with-meta.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Plugin Name: Test Plugin for WPGraphQL 4 | * Version: 1.0.0 5 | * Description: A plugin with WPGraphQL in the meta. 6 | */ 7 | 8 | // Exit if accessed directly. 9 | if ( ! defined( 'ABSPATH' ) ) { 10 | exit; 11 | } 12 | -------------------------------------------------------------------------------- /tests/_data/plugins/plugin-with-requires.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Plugin Name: Test Plugin With Requires Header 4 | * Version: 1.0.0 5 | * Description: A plugin with headers. 6 | * Requires Plugins: wp-graphql 7 | */ 8 | 9 | // Exit if accessed directly. 10 | if ( ! defined( 'ABSPATH' ) ) { 11 | exit; 12 | } 13 | -------------------------------------------------------------------------------- /tests/_data/templates/custom-i18n.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Template Name: カスタムテンプレート 4 | */ 5 | -------------------------------------------------------------------------------- /tests/_data/templates/custom.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Template Name: My custom template 4 | */ 5 | -------------------------------------------------------------------------------- /tests/_data/templates/תבנית-שלי.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Template Name: תבנית שלי 4 | */ 5 | -------------------------------------------------------------------------------- /tests/_envs/docker.yml: -------------------------------------------------------------------------------- 1 | modules: 2 | config: 3 | WPDb: 4 | dsn: 'mysql:host=mysql_test;dbname=wpgraphql_test' 5 | password: 'testing' 6 | WPLoader: 7 | dbHost: "mysql_test" 8 | dbPassword: "testing" 9 | -------------------------------------------------------------------------------- /tests/_output/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /tests/_support/AcceptanceTester.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | 4 | /** 5 | * Inherited Methods 6 | * @method void wantToTest($text) 7 | * @method void wantTo($text) 8 | * @method void execute($callable) 9 | * @method void expectTo($prediction) 10 | * @method void expect($prediction) 11 | * @method void amGoingTo($argumentation) 12 | * @method void am($role) 13 | * @method void lookForwardTo($achieveValue) 14 | * @method void comment($description) 15 | * @method \Codeception\Lib\Friend haveFriend($name, $actorClass = NULL) 16 | * 17 | * @SuppressWarnings(PHPMD) 18 | */ 19 | class AcceptanceTester extends \Codeception\Actor 20 | { 21 | use _generated\AcceptanceTesterActions; 22 | 23 | /** 24 | * Define custom actions here 25 | */ 26 | } 27 | -------------------------------------------------------------------------------- /tests/_support/FunctionalTester.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | 4 | /** 5 | * Inherited Methods 6 | * @method void wantToTest($text) 7 | * @method void wantTo($text) 8 | * @method void execute($callable) 9 | * @method void expectTo($prediction) 10 | * @method void expect($prediction) 11 | * @method void amGoingTo($argumentation) 12 | * @method void am($role) 13 | * @method void lookForwardTo($achieveValue) 14 | * @method void comment($description) 15 | * @method \Codeception\Lib\Friend haveFriend($name, $actorClass = NULL) 16 | * 17 | * @SuppressWarnings(PHPMD) 18 | */ 19 | class FunctionalTester extends \Codeception\Actor 20 | { 21 | use _generated\FunctionalTesterActions; 22 | 23 | /** 24 | * Define custom actions here 25 | */ 26 | } 27 | -------------------------------------------------------------------------------- /tests/_support/Helper/Acceptance.php: -------------------------------------------------------------------------------- 1 | <?php 2 | namespace Helper; 3 | 4 | // here you can define custom actions 5 | // all public methods declared in helper class will be available in $I 6 | 7 | class Acceptance extends \Codeception\Module { 8 | 9 | 10 | } 11 | -------------------------------------------------------------------------------- /tests/_support/Helper/Functional.php: -------------------------------------------------------------------------------- 1 | <?php 2 | namespace Helper; 3 | 4 | // here you can define custom actions 5 | // all public methods declared in helper class will be available in $I 6 | 7 | class Functional extends \Codeception\Module { 8 | 9 | 10 | } 11 | -------------------------------------------------------------------------------- /tests/_support/Helper/Unit.php: -------------------------------------------------------------------------------- 1 | <?php 2 | namespace Helper; 3 | 4 | // here you can define custom actions 5 | // all public methods declared in helper class will be available in $I 6 | 7 | class Unit extends \Codeception\Module { 8 | 9 | 10 | } 11 | -------------------------------------------------------------------------------- /tests/_support/Helper/Wpunit.php: -------------------------------------------------------------------------------- 1 | <?php 2 | namespace Helper; 3 | 4 | // here you can define custom actions 5 | // all public methods declared in helper class will be available in $I 6 | 7 | class Wpunit extends \Codeception\Module { 8 | 9 | 10 | } 11 | -------------------------------------------------------------------------------- /tests/_support/UnitTester.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | 4 | /** 5 | * Inherited Methods 6 | * @method void wantToTest($text) 7 | * @method void wantTo($text) 8 | * @method void execute($callable) 9 | * @method void expectTo($prediction) 10 | * @method void expect($prediction) 11 | * @method void amGoingTo($argumentation) 12 | * @method void am($role) 13 | * @method void lookForwardTo($achieveValue) 14 | * @method void comment($description) 15 | * @method \Codeception\Lib\Friend haveFriend($name, $actorClass = NULL) 16 | * 17 | * @SuppressWarnings(PHPMD) 18 | */ 19 | class UnitTester extends \Codeception\Actor 20 | { 21 | use _generated\UnitTesterActions; 22 | 23 | /** 24 | * Define custom actions here 25 | */ 26 | } 27 | -------------------------------------------------------------------------------- /tests/_support/WpunitTester.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | 4 | /** 5 | * Inherited Methods 6 | * @method void wantToTest($text) 7 | * @method void wantTo($text) 8 | * @method void execute($callable) 9 | * @method void expectTo($prediction) 10 | * @method void expect($prediction) 11 | * @method void amGoingTo($argumentation) 12 | * @method void am($role) 13 | * @method void lookForwardTo($achieveValue) 14 | * @method void comment($description) 15 | * @method \Codeception\Lib\Friend haveFriend($name, $actorClass = NULL) 16 | * 17 | * @SuppressWarnings(PHPMD) 18 | */ 19 | class WpunitTester extends \Codeception\Actor 20 | { 21 | use _generated\WpunitTesterActions; 22 | 23 | /** 24 | * Define custom actions here 25 | */ 26 | } 27 | -------------------------------------------------------------------------------- /tests/_support/_generated/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /tests/acceptance.suite.dist.yml: -------------------------------------------------------------------------------- 1 | # Codeception Test Suite Configuration 2 | # 3 | # Suite for acceptance tests. 4 | # Perform tests in browser using the WPWebDriver or WPBrowser. 5 | # Use WPDb to set up your initial database fixture. 6 | # If you need both WPWebDriver and WPBrowser tests - create a separate suite. 7 | 8 | actor: AcceptanceTester 9 | modules: 10 | enabled: 11 | - Asserts 12 | - REST 13 | - WPBrowser 14 | - WPDb 15 | - WPLoader 16 | config: 17 | WPDb: 18 | cleanup: false 19 | -------------------------------------------------------------------------------- /tests/acceptance/PluginActivatedCest.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | class PluginActivatedCest { 4 | public function seePluginActivated( AcceptanceTester $I ) { 5 | $I->loginAsAdmin(); 6 | $I->amOnPluginsPage(); 7 | $I->seePluginActivated( 'wp-graphql' ); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/acceptance/TwoDomainsSupportedCest.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | class DifferentLocalDomainsSupportedCest { 4 | 5 | public function queryDifferentLocalDomainsTest( AcceptanceTester $I ) { 6 | $domains = [ 7 | 'localhost', 8 | 'wp.localhost', 9 | 'wp2.localhost', 10 | 'foo.bar', 11 | 'foo.bar.localhost', 12 | ]; 13 | foreach ( $domains as $hostname ) { 14 | $I->haveHttpHeader( 'Host', $hostname ); 15 | $I->sendGet( 'graphql', [ 'query' => '{__typename}' ] ); 16 | $I->seeResponseCodeIs( 200 ); 17 | $I->seeResponseContainsJson( 18 | [ 19 | 'data' => [ 20 | '__typename' => 'RootQuery', 21 | ], 22 | ] 23 | ); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/e2e/config/global-setup.js: -------------------------------------------------------------------------------- 1 | /** 2 | * External dependencies 3 | */ 4 | import { request } from '@playwright/test'; 5 | 6 | /** 7 | * WordPress dependencies 8 | */ 9 | import { RequestUtils } from '@wordpress/e2e-test-utils-playwright'; 10 | 11 | /** 12 | * 13 | * @param {import('@playwright/test').FullConfig} config 14 | * @return {Promise<void>} 15 | */ 16 | async function globalSetup( config ) { 17 | const { storageState, baseURL } = config.projects[ 0 ].use; 18 | const storageStatePath = 19 | typeof storageState === 'string' ? storageState : undefined; 20 | 21 | const requestContext = await request.newContext( { 22 | baseURL, 23 | } ); 24 | 25 | const requestUtils = new RequestUtils( requestContext, { 26 | storageStatePath, 27 | } ); 28 | 29 | // Authenticate and save the storageState to disk. 30 | await requestUtils.setupRest(); 31 | 32 | // Reset the test environment before running the tests. 33 | await Promise.all( [ 34 | requestUtils.activateTheme( 'twentytwentyone' ), 35 | requestUtils.deleteAllPosts(), 36 | requestUtils.deleteAllBlocks(), 37 | requestUtils.resetPreferences(), 38 | ] ); 39 | 40 | await requestContext.dispose(); 41 | } 42 | 43 | export default globalSetup; 44 | -------------------------------------------------------------------------------- /tests/e2e/playwright.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * External dependencies 3 | */ 4 | import path from 'node:path'; 5 | import { defineConfig } from '@playwright/test'; 6 | 7 | /** 8 | * WordPress dependencies 9 | */ 10 | const baseConfig = require( '@wordpress/scripts/config/playwright.config' ); 11 | 12 | process.env.WP_ARTIFACTS_PATH ??= path.join( process.cwd(), 'artifacts' ); 13 | process.env.STORAGE_STATE_PATH ??= path.join( 14 | process.env.WP_ARTIFACTS_PATH, 15 | 'storage-states/admin.json' 16 | ); 17 | 18 | const config = defineConfig( { 19 | ...baseConfig, 20 | globalSetup: require.resolve( './config/global-setup.js' ), 21 | webServer: { 22 | ...baseConfig.webServer, 23 | command: 'npm run wp-env -- start', 24 | }, 25 | } ); 26 | 27 | export default config; 28 | -------------------------------------------------------------------------------- /tests/e2e/plugins/README.md: -------------------------------------------------------------------------------- 1 | # WordPress Plugins 2 | 3 | These are custom WordPress plugins specifically designed for end-to-end (e2e) testing of the WPGraphQL plugin. They are not intended for production use but serve to facilitate testing by adding mock functionalities and settings. 4 | -------------------------------------------------------------------------------- /tests/e2e/plugins/settings-page-spec/settings-page-spec.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Plugin Name: Settings Page Spec 4 | * Description: This plugin is specifically used for end-to-end (e2e) testing of the WPGraphQL plugin. It registers settings sections and fields for testing purposes. 5 | */ 6 | 7 | // Register settings sections and fields for testing. 8 | add_action( 9 | 'graphql_register_settings', 10 | static function () { 11 | register_graphql_settings_section( 12 | 'graphql_section_a_settings', 13 | [ 14 | 'title' => __( 'Section A Settings', 'settings-page-spec' ), 15 | 'desc' => __( 'Settings for section A', 'settings-page-spec' ), 16 | ] 17 | ); 18 | 19 | register_graphql_settings_field( 20 | 'graphql_section_a_settings', 21 | [ 22 | 'name' => 'graphql_section_a_checkbox', 23 | 'label' => __( 'Section A Checkbox Option', 'settings-page-spec' ), 24 | 'desc' => __( 'This is a checkbox option for section A', 'settings-page-spec' ), 25 | 'type' => 'checkbox', 26 | ] 27 | ); 28 | 29 | register_graphql_settings_section( 30 | 'graphql_section_b_settings', 31 | [ 32 | 'title' => __( 'Section B Settings', 'settings-page-spec' ), 33 | 'desc' => __( 'Settings for section B', 'settings-page-spec' ), 34 | ] 35 | ); 36 | 37 | register_graphql_settings_field( 38 | 'graphql_section_b_settings', 39 | [ 40 | 'name' => 'graphql_section_b_checkbox', 41 | 'label' => __( 'Section B Checkbox Option', 'settings-page-spec' ), 42 | 'desc' => __( 'This is a checkbox option for section B', 'settings-page-spec' ), 43 | 'type' => 'checkbox', 44 | ] 45 | ); 46 | } 47 | ); 48 | -------------------------------------------------------------------------------- /tests/functional.suite.dist.yml: -------------------------------------------------------------------------------- 1 | # Codeception Test Suite Configuration 2 | # 3 | # Suite for functional tests 4 | # Emulate web requests and make WordPress process them 5 | 6 | actor: FunctionalTester 7 | modules: 8 | enabled: 9 | - Asserts 10 | - REST 11 | - WPBrowser 12 | - WPDb 13 | - WPLoader 14 | config: 15 | WPDb: 16 | cleanup: false 17 | bootstrap: bootstrap.php 18 | -------------------------------------------------------------------------------- /tests/functional/ApolloPreflightRequestCept.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | $I = new FunctionalTester( $scenario ); 4 | $I->wantTo( 'Send a preflight Options request like Apollo and check the response' ); 5 | 6 | 7 | $I->haveHttpHeader( 'Content-Type', 'application/json' ); 8 | $I->sendOPTIONS( 'http://localhost/graphql' ); 9 | 10 | $I->seeResponseCodeIs( 200 ); 11 | 12 | $response = $I->canSeeHttpHeader( 'Access-Control-Allow-Origin' ); 13 | 14 | $expected = $I->grabHttpHeader( 'Access-Control-Allow-Origin' ); 15 | $I->assertEquals( '*', $expected ); 16 | 17 | $expected = $I->grabHttpHeader( 'Content-Type' ); 18 | $I->assertEquals( 'application/json ; charset=UTF-8', $expected ); 19 | 20 | $access_control_allow_headers = $I->grabHttpHeader( 'Access-Control-Allow-Headers' ); 21 | $headers = explode( ', ', $access_control_allow_headers ); 22 | 23 | codecept_debug( $headers ); 24 | 25 | $I->assertContains( 'Content-Type', $headers ); 26 | $I->assertContains( 'Authorization', $headers ); 27 | -------------------------------------------------------------------------------- /tests/functional/BatchQueriesCept.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | $I = new FunctionalTester( $scenario ); 4 | $I->wantTo( 'Test batch queries' ); 5 | 6 | $options = [ 7 | 'batch_queries_enabled' => 'on', 8 | ]; 9 | 10 | $I->haveOptionInDatabase( 'graphql_general_settings', $options ); 11 | 12 | $I->havePostInDatabase( 13 | [ 14 | 'post_type' => 'post', 15 | 'post_status' => 'publish', 16 | 'post_title' => 'test post', 17 | 'post_content' => 'test content', 18 | ] 19 | ); 20 | 21 | $I->haveHttpHeader( 'Content-Type', 'application/json' ); 22 | 23 | $I->sendPost( 24 | 'http://localhost/graphql', 25 | json_encode( 26 | [ 27 | [ 28 | 'query' => '{posts{nodes{id,title}}}', 29 | ], 30 | [ 31 | 'query' => '{posts{nodes{id,uri}}}', 32 | ], 33 | ] 34 | ) 35 | ); 36 | 37 | $I->seeResponseCodeIs( 200 ); 38 | $I->seeResponseIsJson(); 39 | $response = $I->grabResponse(); 40 | $response_array = json_decode( $response, true ); 41 | 42 | $I->assertArrayNotHasKey( 'errors', $response_array[0], 'Batch Queries are enabled and the first query should be valid' ); 43 | $I->assertNotEmpty( $response_array[0]['data'], 'Batch Queries are enabled and the first query should be valid' ); 44 | $I->assertArrayNotHasKey( 'errors', $response_array[1], 'Batch Queries are enabled and the second query should be valid' ); 45 | $I->assertNotEmpty( $response_array[1]['data'], 'Batch Queries are enabled and the second query should be valid' ); 46 | -------------------------------------------------------------------------------- /tests/functional/BatchQueriesDisabledCept.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | $I = new FunctionalTester( $scenario ); 4 | $I->wantTo( 'Test batch queries return errors when batching is disabled' ); 5 | 6 | $options = [ 7 | 'batch_queries_enabled' => 'off', 8 | ]; 9 | 10 | $I->haveOptionInDatabase( 'graphql_general_settings', $options ); 11 | 12 | $settings = $I->grabOptionFromDatabase( 'graphql_general_settings' ); 13 | 14 | $I->haveHttpHeader( 'Content-Type', 'application/json' ); 15 | 16 | $I->sendPost( 17 | 'http://localhost/graphql', 18 | json_encode( 19 | [ 20 | [ 21 | 'query' => '{posts{nodes{id,title}}}', 22 | ], 23 | [ 24 | 'query' => '{posts{nodes{id,uri}}}', 25 | ], 26 | ] 27 | ) 28 | ); 29 | 30 | $I->seeResponseCodeIs( 500 ); 31 | $I->seeResponseIsJson(); 32 | $response = $I->grabResponse(); 33 | $response_array = json_decode( $response, true ); 34 | 35 | $I->assertSame( 'off', $settings['batch_queries_enabled'] ); 36 | 37 | $I->assertArrayHasKey( 'errors', $response_array, 'Batch Queries are NOT enabled and the first query should have errors' ); 38 | $I->assertArrayNotHasKey( 'data', $response_array, 'Batch Queries are NOT enabled and the first query should not have data' ); 39 | -------------------------------------------------------------------------------- /tests/functional/ContentTypeHeaderCept.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | $I = new FunctionalTester($scenario); 4 | 5 | $I->wantTo('Ensure 415 status code is returned when content-type header is missing or incorrect'); 6 | 7 | // Test with no content-type header 8 | $I->sendPOST('http://localhost/graphql', json_encode([ 9 | 'query' => '{posts{nodes{id}}}' 10 | ])); 11 | $I->seeResponseCodeIs(415); 12 | $I->seeResponseContainsJson([ 13 | 'errors' => [ 14 | [ 15 | 'message' => 'HTTP POST requests must have Content-Type: application/json header. Received: ' 16 | ] 17 | ] 18 | ]); 19 | 20 | // Test with incorrect content-type header 21 | $I->haveHttpHeader('Content-Type', 'text/plain'); 22 | $I->sendPOST('http://localhost/graphql', json_encode([ 23 | 'query' => '{posts{nodes{id}}}' 24 | ])); 25 | $I->seeResponseCodeIs(415); 26 | $I->seeResponseContainsJson([ 27 | 'errors' => [ 28 | [ 29 | 'message' => 'HTTP POST requests must have Content-Type: application/json header. Received: text/plain' 30 | ] 31 | ] 32 | ]); 33 | 34 | // Verify that application/json content-type works correctly 35 | $I->haveHttpHeader('Content-Type', 'application/json'); 36 | $I->sendPOST('http://localhost/graphql', json_encode([ 37 | 'query' => '{posts{nodes{id}}}' 38 | ])); 39 | $I->seeResponseCodeIs(200); 40 | 41 | // Verify that application/json with charset works 42 | $I->haveHttpHeader('Content-Type', 'application/json; charset=utf-8'); 43 | $I->sendPOST('http://localhost/graphql', json_encode([ 44 | 'query' => '{posts{nodes{id}}}' 45 | ])); 46 | $I->seeResponseCodeIs(200); 47 | 48 | -------------------------------------------------------------------------------- /tests/functional/GraphqlSettingsPageCept.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | $I = new FunctionalTester( $scenario ); 4 | 5 | $I->wantTo( 'Test GraphQL Settings Page Renders and Saves as Expected' ); 6 | 7 | $I->loginAsAdmin(); 8 | 9 | $I->amOnAdminPage( '/admin.php?page=graphql-settings' ); 10 | 11 | $I->see( 'WPGraphQL General Settings' ); 12 | 13 | // Verify that the default value is populated 14 | $I->seeOptionIsSelected( 'graphql_general_settings[tracing_user_role]', 'Administrator' ); 15 | $I->seeOptionIsSelected( 'graphql_general_settings[query_log_user_role]', 'Administrator' ); 16 | -------------------------------------------------------------------------------- /tests/functional/bootstrap.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | // Disable updates to prevent WP from going into maintenance mode while tests run 4 | add_filter( 'enable_maintenance_mode', '__return_false' ); 5 | add_filter( 'wp_auto_update_core', '__return_false' ); 6 | add_filter( 'auto_update_plugin', '__return_false' ); 7 | add_filter( 'auto_update_theme', '__return_false' ); 8 | -------------------------------------------------------------------------------- /tests/wpunit.suite.dist.yml: -------------------------------------------------------------------------------- 1 | # Codeception Test Suite Configuration 2 | # 3 | # Suite for unit or integration tests that require WordPress functions and classes. 4 | actor: WpunitTester 5 | modules: 6 | enabled: 7 | - Asserts 8 | - WPLoader 9 | disabled: 10 | - WPDb 11 | - WPBrowser 12 | config: 13 | WPDb: 14 | cleanup: false 15 | WPLoader: 16 | multisite: '%MULTISITE%' 17 | plugins: 18 | - wp-graphql/wp-graphql.php 19 | activatePlugins: 20 | - wp-graphql/wp-graphql.php 21 | configFile: 22 | - 'tests/_data/config.php' 23 | -------------------------------------------------------------------------------- /tests/wpunit/DebugLogTest.php: -------------------------------------------------------------------------------- 1 | <?php 2 | class DebugLogTest extends \Codeception\TestCase\WPTestCase { 3 | 4 | public $admin; 5 | 6 | public function setUp(): void { 7 | parent::setUp(); 8 | $this->admin = $this->factory()->user->create( 9 | [ 10 | 'role' => 'administrator', 11 | ] 12 | ); 13 | WPGraphQL::clear_schema(); 14 | } 15 | 16 | public function tearDown(): void { 17 | parent::tearDown(); 18 | } 19 | 20 | public function testDebugLogShowsLogs() { 21 | 22 | wp_set_current_user( $this->admin ); 23 | graphql_debug( 'Test message', [ 'type' => 'TEST' ] ); 24 | $query = '{posts{nodes{id}}}'; 25 | $actual = graphql( [ 'query' => $query ] ); 26 | codecept_debug( $actual ); 27 | $messages = isset( $actual['extensions']['debug'] ) ? $actual['extensions']['debug'] : null; 28 | $this->assertNotEmpty( $messages ); 29 | $key = array_search( 'TEST', array_column( $messages, 'type' ) ); 30 | $this->assertEquals( 'TEST', $messages[ $key ]['type'] ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/wpunit/IsGraphqlHttpRequestTest.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | class IsGraphqlHttpRequestTest extends \Codeception\TestCase\WPTestCase { 4 | 5 | /** 6 | * Must match with the one in the codeception config 7 | */ 8 | private $host = 'localhost'; 9 | 10 | 11 | public function tearDown(): void { 12 | parent::tearDown(); 13 | WPGraphQL::clear_schema(); 14 | } 15 | 16 | public function testBasic() { 17 | $_SERVER['HTTP_HOST'] = $this->host; 18 | $_SERVER['REQUEST_URI'] = '/graphql'; 19 | $this->assertEquals( true, is_graphql_http_request() ); 20 | } 21 | 22 | /** 23 | * Request from wp-graphqi comes to urls like 24 | * https://localhost/index.php?graphql 25 | */ 26 | public function testGraphiqlRequest() { 27 | $_SERVER['HTTP_HOST'] = $this->host; 28 | $_SERVER['REQUEST_URI'] = '/index.php'; 29 | $_GET['graphql'] = ''; 30 | $this->assertEquals( true, is_graphql_http_request() ); 31 | } 32 | 33 | public function testUnknownPath() { 34 | $_SERVER['HTTP_HOST'] = $this->host; 35 | $_SERVER['REQUEST_URI'] = '/other'; 36 | $this->assertEquals( false, is_graphql_http_request() ); 37 | } 38 | 39 | public function testUnknownPathWithGraphqlString() { 40 | $_SERVER['HTTP_HOST'] = $this->host; 41 | $_SERVER['REQUEST_URI'] = '/other/graphql/ding'; 42 | $this->assertEquals( false, is_graphql_http_request() ); 43 | } 44 | 45 | public function testUnknownPathEndingWithGraphql() { 46 | $_SERVER['HTTP_HOST'] = $this->host; 47 | $_SERVER['REQUEST_URI'] = '/other/graphql'; 48 | $this->assertEquals( false, is_graphql_http_request() ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /tests/wpunit/MenuItemConnectionResolverTest.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | class MenuItemConnectionResolverTest extends \Codeception\TestCase\WPTestCase { 4 | 5 | public function setUp(): void { 6 | // before 7 | parent::setUp(); 8 | 9 | // your set up methods here 10 | WPGraphQL::clear_schema(); 11 | } 12 | 13 | public function tearDown(): void { 14 | // your tear down methods here 15 | WPGraphQL::clear_schema(); 16 | // then 17 | parent::tearDown(); 18 | } 19 | 20 | public function testMenuItemConnectionResolverWithNoMenuItem() { 21 | 22 | $query = ' 23 | { 24 | menuItems { 25 | nodes { 26 | id 27 | } 28 | } 29 | } 30 | '; 31 | 32 | $actual = do_graphql_request( $query ); 33 | $this->assertEmpty( $actual['data']['menuItems']['nodes'] ); 34 | $this->assertArrayNotHasKey( 'errors', $actual ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tests/wpunit/PluginCompatibilityTest.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | /** 4 | * Class PluginCompatibilityTest 5 | * 6 | * Various tests to check for compatibility with other plugins in the ecosystem 7 | */ 8 | class PluginCompatibilityTest extends \Tests\WPGraphQL\TestCase\WPGraphQLTestCase { 9 | 10 | public function setUp(): void { 11 | // before 12 | parent::setUp(); 13 | 14 | $this->admin = $this->factory()->user->create( 15 | [ 16 | 'role' => 'administrator', 17 | ] 18 | ); 19 | } 20 | 21 | public function tearDown(): void { 22 | 23 | // then 24 | parent::tearDown(); 25 | } 26 | 27 | public function testAmpWpCompatibility() { 28 | 29 | add_filter( 30 | 'parse_request', 31 | static function ( \WP $wp ) { 32 | return $wp; 33 | } 34 | ); 35 | 36 | $post_id = $this->factory()->post->create( 37 | [ 38 | 'post_type' => 'post', 39 | 'post_status' => 'publish', 40 | ] 41 | ); 42 | 43 | $slug = get_post( $post_id )->post_name; 44 | 45 | $query = ' 46 | query PostBySlug( $slug: ID! ) { 47 | post( id: $slug idType: SLUG ) { 48 | databaseId 49 | } 50 | } 51 | '; 52 | $actual = graphql( 53 | [ 54 | 'query' => $query, 55 | 'variables' => [ 'slug' => $slug ], 56 | ] 57 | ); 58 | 59 | $this->assertQuerySuccessful( 60 | $actual, 61 | [ 62 | $this->expectedField( 'post.databaseId', $post_id ), 63 | ] 64 | ); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /tests/wpunit/README.md: -------------------------------------------------------------------------------- 1 | # WPUnit Tests 2 | These are tests utilizing the WP_UnitTestCase. They're really integration tests more than "unit" tests, as they 3 | test functionality of any particular piece of code in context of running with 4 | WordPress core (and potentially other plugins or theme code). 5 | 6 | There are helper functions/factories for creating dummy data and making assertions against that data, etc. 7 | 8 | These tests help ensure that WPGraphQL works with WordPress as it should. 9 | -------------------------------------------------------------------------------- /tests/wpunit/ShouldShowAdminToolbarQueryTest.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | class ShouldShowAdminToolbarQueryTest extends \Codeception\TestCase\WPTestCase { 4 | 5 | public function setUp(): void { 6 | parent::setUp(); 7 | WPGraphQL::clear_schema(); 8 | } 9 | 10 | public function tearDown(): void { 11 | WPGraphQL::clear_schema(); 12 | parent::tearDown(); 13 | } 14 | 15 | public function testViewerQuery() { 16 | 17 | $user_id = $this->factory->user->create( 18 | [ 19 | 'role' => 'administrator', 20 | ] 21 | ); 22 | 23 | $query = ' 24 | { 25 | viewer{ 26 | userId 27 | roles { 28 | nodes { 29 | name 30 | } 31 | } 32 | shouldShowAdminToolbar 33 | } 34 | } 35 | '; 36 | 37 | /** 38 | * Set the current user so we can properly test the viewer query 39 | */ 40 | wp_set_current_user( $user_id ); 41 | 42 | $actual = graphql( [ 'query' => $query ] ); 43 | 44 | codecept_debug( $actual ); 45 | 46 | $this->assertArrayNotHasKey( 'errors', $actual ); 47 | $this->assertEquals( $user_id, $actual['data']['viewer']['userId'] ); 48 | $this->assertSame( true, $actual['data']['viewer']['shouldShowAdminToolbar'] ); 49 | 50 | // Update the user's preference to not show admin bar. 51 | update_user_meta( $user_id, 'show_admin_bar_front', 'false' ); 52 | 53 | $actual = graphql( [ 'query' => $query ] ); 54 | 55 | codecept_debug( $actual ); 56 | 57 | $this->assertArrayNotHasKey( 'errors', $actual ); 58 | $this->assertEquals( $user_id, $actual['data']['viewer']['userId'] ); 59 | $this->assertSame( false, $actual['data']['viewer']['shouldShowAdminToolbar'] ); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /tests/wpunit/UserRoleEnumTest.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | use WPGraphQL\Type\Enum\UserRoleEnum; 4 | 5 | class UserRoleEnumTest extends \Codeception\TestCase\WPTestCase { 6 | 7 | public function setUp(): void { 8 | // before 9 | parent::setUp(); 10 | 11 | // your set up methods here 12 | WPGraphQL::clear_schema(); 13 | } 14 | 15 | public function tearDown(): void { 16 | // your tear down methods here 17 | WPGraphQL::clear_schema(); 18 | // then 19 | parent::tearDown(); 20 | } 21 | 22 | /** 23 | * Test filter for WP enum type invokes. 24 | * 25 | * @throws \Exception 26 | */ 27 | public function testUserEdittableRoleWhenNameEmpty() { 28 | 29 | /** 30 | * Modify the user role enums for testing null name. 31 | * Test roles that don't have an explicit name, don't fail during type registration. 32 | */ 33 | add_filter( 34 | 'editable_roles', 35 | static function ( $roles ) { 36 | return [ 37 | 'foo' => [ 38 | 'name' => 'Foo', 39 | 'extra' => 'hello-foo', 40 | ], 41 | 'bar' => [ 42 | 'name' => null, 43 | 'extra' => 'hello-bar', 44 | ], 45 | 'biz' => [ 46 | 'extra' => 'hello-biz', 47 | ], 48 | ]; 49 | } 50 | ); 51 | 52 | /** 53 | * Invoke the user role enum registration. 54 | */ 55 | UserRoleEnum::register_type(); 56 | $editable_roles = get_editable_roles(); 57 | $this->assertArrayHasKey( 'foo', $editable_roles ); 58 | $this->assertArrayHasKey( 'bar', $editable_roles ); 59 | $this->assertArrayHasKey( 'biz', $editable_roles ); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /tests/wpunit/UtilsTest.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | class UtilsTest extends \Tests\WPGraphQL\TestCase\WPGraphQLTestCase { 4 | 5 | 6 | public function testGetQueryId() { 7 | 8 | $query_without_spaces = '{posts{nodes{id,title}}}'; 9 | $query_with_spaces = '{ posts { nodes { id, title } } }'; 10 | $query_with_line_breaks = ' 11 | { 12 | posts { 13 | nodes { 14 | id 15 | title 16 | } 17 | } 18 | }'; 19 | 20 | $id1 = \WPGraphQL\Utils\Utils::get_query_id( $query_without_spaces ); 21 | $id2 = \WPGraphQL\Utils\Utils::get_query_id( $query_with_spaces ); 22 | $id3 = \WPGraphQL\Utils\Utils::get_query_id( $query_with_line_breaks ); 23 | 24 | codecept_debug( 25 | [ 26 | $id1, 27 | $id2, 28 | $id3, 29 | ] 30 | ); 31 | 32 | // differently formatted versions of the same query should 33 | // all produce the same query_id 34 | $this->assertSame( $id1, $id2 ); 35 | $this->assertSame( $id2, $id3 ); 36 | $this->assertSame( $id1, $id3 ); 37 | 38 | $invalid_query = '{ some { malformatted { query...'; 39 | 40 | // if an invalid query is passed, we should get a null response 41 | $this->assertNull( \WPGraphQL\Utils\Utils::get_query_id( $invalid_query ) ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/wpunit/ViewerQueryTest.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | class ViewerQueryTest extends \Codeception\TestCase\WPTestCase { 4 | 5 | public function setUp(): void { 6 | parent::setUp(); 7 | WPGraphQL::clear_schema(); 8 | } 9 | 10 | public function tearDown(): void { 11 | WPGraphQL::clear_schema(); 12 | parent::tearDown(); 13 | } 14 | 15 | public function testViewerQuery() { 16 | 17 | $user_id = $this->factory->user->create( 18 | [ 19 | 'role' => 'administrator', 20 | ] 21 | ); 22 | 23 | $query = ' 24 | { 25 | viewer{ 26 | userId 27 | roles { 28 | nodes { 29 | name 30 | } 31 | } 32 | } 33 | } 34 | '; 35 | 36 | $actual = do_graphql_request( $query ); 37 | 38 | /** 39 | * We should get an error because no user is logged in right now 40 | */ 41 | $this->assertArrayNotHasKey( 'errors', $actual ); 42 | $this->assertNull( $actual['data']['viewer'] ); 43 | 44 | /** 45 | * Set the current user so we can properly test the viewer query 46 | */ 47 | wp_set_current_user( $user_id ); 48 | $actual = graphql( [ 'query' => $query ] ); 49 | 50 | codecept_debug( $actual ); 51 | 52 | $this->assertNotEmpty( $actual ); 53 | $this->assertArrayNotHasKey( 'errors', $actual ); 54 | $this->assertEquals( $user_id, $actual['data']['viewer']['userId'] ); 55 | $this->assertSame( 'administrator', $actual['data']['viewer']['roles']['nodes'][0]['name'] ); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /tests/wpunit/WPEnumTypeTest.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | use WPGraphQL\Type\WPEnumType; 4 | 5 | class WPEnumTypeTest extends \Codeception\TestCase\WPTestCase { 6 | 7 | public function setUp(): void { 8 | // before 9 | parent::setUp(); 10 | // your set up methods here 11 | WPGraphQL::clear_schema(); 12 | } 13 | 14 | public function tearDown(): void { 15 | // your tear down methods here 16 | WPGraphQL::clear_schema(); 17 | // then 18 | parent::tearDown(); 19 | } 20 | 21 | /** 22 | * Test filter for WP enum type invokes. 23 | * 24 | * @throws \Exception 25 | */ 26 | public function testEnumValuesFilterRuns() { 27 | 28 | /** 29 | * Filter fields onto the Enum 30 | */ 31 | add_filter( 32 | 'graphql_enum_values', 33 | static function ( $values ) { 34 | 35 | foreach ( $values as $key => $value ) { 36 | $value['name'] = $value['name'] . '-CHANGED'; 37 | $values[ $key ] = $value; 38 | } 39 | 40 | return $values; 41 | } 42 | ); 43 | 44 | $values = [ 45 | 'ONE' => [ 46 | 'name' => 'ONE', 47 | 'value' => 'oneone', 48 | 'description' => __( 'Enum for one.', 'wp-graphql' ), 49 | ], 50 | 'TWO' => [ 51 | 'name' => 'TWO', 52 | 'value' => 'twotwo', 53 | 'description' => __( 'Enum for two.', 'wp-graphql' ), 54 | ], 55 | ]; 56 | $config['values'] = $values; 57 | $config['name'] = 'WPEnumTestOne'; 58 | $enum_object = new WPEnumType( $config ); 59 | $actual = $enum_object->getValues(); 60 | 61 | $this->assertEquals( 'ONE-CHANGED', $actual[0]->name ); 62 | $this->assertEquals( 'TWO-CHANGED', $actual[1]->name ); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /tests/wpunit/WPGraphQLAccessFunctionsTest.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | class WPGraphQLAccessFunctionsTest extends \Codeception\TestCase\WPTestCase { 4 | 5 | public function setUp(): void { 6 | parent::setUp(); 7 | } 8 | 9 | public function tearDown(): void { 10 | parent::tearDown(); 11 | } 12 | 13 | /** 14 | * Tests the access function that is available to format strings to GraphQL friendly format 15 | */ 16 | public function testGraphQLFormatFieldName() { 17 | 18 | $actual = graphql_format_field_name( 'This is some field name' ); 19 | $expected = 'thisIsSomeFieldName'; 20 | 21 | $this->assertEquals( $expected, $actual ); 22 | } 23 | } 24 | --------------------------------------------------------------------------------