Overview
  • Namespace
  • Class

Namespaces

  • WPGraphQL
    • Data
    • Type
      • Avatar
      • Comment
        • Connection
      • CommentAuthor
      • EditLock
      • Enum
      • MediaItem
        • Mutation
      • Plugin
        • Connection
      • PostObject
        • Connection
        • Mutation
      • PostType
      • Setting
      • Taxonomy
      • TermObject
        • Connection
        • Mutation
      • Theme
        • Connection
      • Union
      • User
        • Connection
        • Mutation
    • Utils

Classes

  • WPGraphQL\AppContext
  • WPGraphQL\Data\Config
  • WPGraphQL\Data\ConnectionResolver
  • WPGraphQL\Data\DataSource
  • WPGraphQL\Data\Loader
  • WPGraphQL\Router
  • WPGraphQL\Type\Avatar\AvatarType
  • WPGraphQL\Type\Comment\CommentQuery
  • WPGraphQL\Type\Comment\CommentType
  • WPGraphQL\Type\Comment\Connection\CommentConnectionArgs
  • WPGraphQL\Type\Comment\Connection\CommentConnectionDefinition
  • WPGraphQL\Type\Comment\Connection\CommentConnectionResolver
  • WPGraphQL\Type\CommentAuthor\CommentAuthorQuery
  • WPGraphQL\Type\CommentAuthor\CommentAuthorType
  • WPGraphQL\Type\EditLock\EditLockType
  • WPGraphQL\Type\Enum\MediaItemStatusEnumType
  • WPGraphQL\Type\Enum\MimeTypeEnumType
  • WPGraphQL\Type\Enum\PostObjectFieldFormatEnumType
  • WPGraphQL\Type\Enum\PostStatusEnumType
  • WPGraphQL\Type\Enum\PostTypeEnumType
  • WPGraphQL\Type\Enum\RelationEnumType
  • WPGraphQL\Type\Enum\TaxonomyEnumType
  • WPGraphQL\Type\MediaItem\MediaItemType
  • WPGraphQL\Type\MediaItem\Mutation\MediaItemCreate
  • WPGraphQL\Type\MediaItem\Mutation\MediaItemDelete
  • WPGraphQL\Type\MediaItem\Mutation\MediaItemMutation
  • WPGraphQL\Type\MediaItem\Mutation\MediaItemUpdate
  • WPGraphQL\Type\Plugin\Connection\PluginConnectionDefinition
  • WPGraphQL\Type\Plugin\Connection\PluginConnectionResolver
  • WPGraphQL\Type\Plugin\PluginQuery
  • WPGraphQL\Type\Plugin\PluginType
  • WPGraphQL\Type\PostObject\Connection\PostObjectConnectionArgs
  • WPGraphQL\Type\PostObject\Connection\PostObjectConnectionArgsDateQuery
  • WPGraphQL\Type\PostObject\Connection\PostObjectConnectionDefinition
  • WPGraphQL\Type\PostObject\Connection\PostObjectConnectionResolver
  • WPGraphQL\Type\PostObject\Mutation\PostObjectCreate
  • WPGraphQL\Type\PostObject\Mutation\PostObjectDelete
  • WPGraphQL\Type\PostObject\Mutation\PostObjectMutation
  • WPGraphQL\Type\PostObject\Mutation\PostObjectUpdate
  • WPGraphQL\Type\PostObject\Mutation\TermObjectDelete
  • WPGraphQL\Type\PostObject\PostObjectQuery
  • WPGraphQL\Type\PostObject\PostObjectType
  • WPGraphQL\Type\PostType\PostTypeType
  • WPGraphQL\Type\RootMutationType
  • WPGraphQL\Type\RootQueryType
  • WPGraphQL\Type\Setting\SettingQuery
  • WPGraphQL\Type\Setting\SettingType
  • WPGraphQL\Type\Taxonomy\TaxonomyType
  • WPGraphQL\Type\TermObject\Connection\TermObjectConnectionArgs
  • WPGraphQL\Type\TermObject\Connection\TermObjectConnectionDefinition
  • WPGraphQL\Type\TermObject\Connection\TermObjectConnectionResolver
  • WPGraphQL\Type\TermObject\Mutation\TermObjectCreate
  • WPGraphQL\Type\TermObject\Mutation\TermObjectMutation
  • WPGraphQL\Type\TermObject\Mutation\TermObjectUpdate
  • WPGraphQL\Type\TermObject\TermObjectQuery
  • WPGraphQL\Type\TermObject\TermObjectType
  • WPGraphQL\Type\Theme\Connection\ThemeConnectionDefinition
  • WPGraphQL\Type\Theme\Connection\ThemeConnectionResolver
  • WPGraphQL\Type\Theme\ThemeType
  • WPGraphQL\Type\Union\CommentAuthorUnionType
  • WPGraphQL\Type\Union\PostObjectUnionType
  • WPGraphQL\Type\Union\TermObjectUnionType
  • WPGraphQL\Type\User\Connection\UserConnectionArgs
  • WPGraphQL\Type\User\Connection\UserConnectionDefinition
  • WPGraphQL\Type\User\Connection\UserConnectionResolver
  • WPGraphQL\Type\User\Mutation\UserCreate
  • WPGraphQL\Type\User\Mutation\UserDelete
  • WPGraphQL\Type\User\Mutation\UserMutation
  • WPGraphQL\Type\User\Mutation\UserUpdate
  • WPGraphQL\Type\User\UserQuery
  • WPGraphQL\Type\User\UserType
  • WPGraphQL\Type\WPEnumType
  • WPGraphQL\Type\WPInputObjectType
  • WPGraphQL\Type\WPObjectType
  • WPGraphQL\Types
  • WPGraphQL\Utils\InstrumentSchema
  • WPGraphQL\WPSchema

Interfaces

  • WPGraphQL\Data\ConnectionResolverInterface
  1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36  37  38  39  40  41  42  43  44  45  46  47  48  49  50  51  52  53  54  55  56  57  58  59  60  61  62  63  64  65  66  67  68  69  70  71  72  73  74  75  76  77  78  79  80  81  82  83  84  85  86  87  88  89  90  91  92  93  94  95  96  97  98  99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 
<?php

namespace WPGraphQL\Utils;

use GraphQL\Error\UserError;
use GraphQL\Executor\Executor;
use GraphQL\Type\Definition\FieldDefinition;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\ResolveInfo;
use WPGraphQL\AppContext;
use WPGraphQL\Type\WPObjectType;

/**
 * Class InstrumentSchema
 *
 * @package WPGraphQL\Data
 */
class InstrumentSchema {

    /**
     * @param \WPGraphQL\WPSchema $schema
     *
     * @return \WPGraphQL\WPSchema
     */
    public static function instrument_schema( \WPGraphQL\WPSchema $schema ) {

        $new_types = [];
        $types     = $schema->getTypeMap();

        if ( ! empty( $types ) && is_array( $types ) ) {
            foreach ( $types as $type_name => $type_object ) {
                if ( $type_object instanceof ObjectType || $type_object instanceof WPObjectType ) {
                    $fields                            = $type_object->getFields();
                    $new_fields                        = self::wrap_fields( $fields, $type_name );
                    $new_type_object                   = $type_object;
                    $new_type_object->name             = ucfirst( esc_html( $type_object->name ) );
                    $new_type_object->description      = esc_html( $type_object->description );
                    $new_type_object->config['fields'] = $new_fields;
                    $new_types[ $type_name ]           = $new_type_object;
                }
            }
        }

        if ( ! empty( $new_types ) && is_array( $new_types ) ) {
            $schema->config['types'] = $new_types;
        }

        return $schema;

    }

    /**
     * Wrap Fields
     *
     * This wraps fields to provide sanitization on fields output by introspection queries (description/deprecation
     * reason) and provides hooks to resolvers.
     *
     * @param array  $fields    The fields configured for a Type
     * @param string $type_name The Type name
     *
     * @return mixed
     */
    protected static function wrap_fields( $fields, $type_name ) {

        if ( ! empty( $fields ) && is_array( $fields ) ) {

            foreach ( $fields as $field_key => $field ) {

                if ( $field instanceof FieldDefinition ) {

                    /**
                     * Get the fields resolve function
                     *
                     * @since 0.0.1
                     */
                    $field_resolver = ! empty( $field->resolveFn ) ? $field->resolveFn : null;

                    /**
                     * Sanitize the description and deprecation reason
                     */
                    $field->description       = ! empty( $field->description ) ? esc_html( $field->description ) : '';
                    $field->deprecationReason = ! empty( $field->deprecationReason ) ? esc_html( $field->deprecationReason ) : '';

                    /**
                     * Replace the existing field resolve method with a new function that captures data about
                     * the resolver to be stored in the resolver_report
                     *
                     * @since 0.0.1
                     *
                     * @param mixed       $source  The source passed down the Resolve Tree
                     * @param array       $args    The args for the field
                     * @param AppContext  $context The AppContext passed down the ResolveTree
                     * @param ResolveInfo $info    The ResolveInfo passed down the ResolveTree
                     *
                     * @use   function|null $field_resolve_function
                     * @use   string $type_name
                     * @use   string $field_key
                     * @use   object $field
                     *
                     * @return mixed
                     * @throws \Exception
                     */
                    $field->resolveFn = function( $source, array $args, AppContext $context, ResolveInfo $info ) use ( $field_resolver, $type_name, $field_key, $field ) {

                        /**
                         * Fire an action BEFORE the field resolves
                         *
                         * @param mixed           $source    The source passed down the Resolve Tree
                         * @param array           $args      The args for the field
                         * @param AppContext      $context   The AppContext passed down the ResolveTree
                         * @param ResolveInfo     $info      The ResolveInfo passed down the ResolveTree
                         * @param string          $type_name The name of the type the fields belong to
                         * @param string          $field_key The name of the field
                         * @param FieldDefinition $field     The Field Definition for the resolving field
                         */
                        do_action( 'graphql_before_resolve_field', $source, $args, $context, $info, $field_resolver, $type_name, $field_key, $field );

                        /**
                         * If the current field doesn't have a resolve function, use the defaultFieldResolver,
                         * otherwise use the $field_resolver
                         */
                        if ( null === $field_resolver || ! is_callable( $field_resolver ) ) {
                            $result = Executor::defaultFieldResolver( $source, $args, $context, $info );
                        } else {
                            $result = call_user_func( $field_resolver, $source, $args, $context, $info );
                        }

                        /**
                         * Fire an action before the field resolves
                         *
                         * @param mixed           $result         The result of the field resolution
                         * @param mixed           $source         The source passed down the Resolve Tree
                         * @param array           $args           The args for the field
                         * @param AppContext      $context        The AppContext passed down the ResolveTree
                         * @param ResolveInfo     $info           The ResolveInfo passed down the ResolveTree
                         * @param string          $type_name      The name of the type the fields belong to
                         * @param string          $field_key      The name of the field
                         * @param FieldDefinition $field          The Field Definition for the resolving field
                         * @param mixed           $field_resolver The default field resolver
                         */
                        $result = apply_filters( 'graphql_resolve_field', $result, $source, $args, $context, $info, $type_name, $field_key, $field, $field_resolver );

                        /**
                         * Fire an action AFTER the field resolves
                         *
                         * @param mixed           $source    The source passed down the Resolve Tree
                         * @param array           $args      The args for the field
                         * @param AppContext      $context   The AppContext passed down the ResolveTree
                         * @param ResolveInfo     $info      The ResolveInfo passed down the ResolveTree
                         * @param string          $type_name The name of the type the fields belong to
                         * @param string          $field_key The name of the field
                         * @param FieldDefinition $field     The Field Definition for the resolving field
                         */
                        do_action( 'graphql_after_resolve_field', $source, $args, $context, $info, $field_resolver, $type_name, $field_key, $field );

                        return $result;

                    };

                }
            }
        }

        /**
         * Return the fields
         */
        return $fields;

    }

    /**
     * Check field permissions when resolving.
     *
     * This takes into account auth params defined in the Schema
     *
     * @param mixed           $source    The source passed down the Resolve Tree
     * @param array           $args      The args for the field
     * @param AppContext      $context   The AppContext passed down the ResolveTree
     * @param ResolveInfo     $info      The ResolveInfo passed down the ResolveTree
     * @param string          $type_name The name of the type the fields belong to
     * @param string          $field_key The name of the field
     * @param FieldDefinition $field     The Field Definition for the resolving field
     *
     * @return bool|mixed
     */
    public static function check_field_permissions( $source, $args, $context, $info, $field_resolver, $type_name, $field_key, $field ) {

        /**
         * Set the default auth error message
         */
        $default_auth_error_message = __( 'You do not have permission to view this', 'wp-graphql' );

        /**
         * Filter the $auth_error
         */
        $auth_error = apply_filters( 'graphql_field_resolver_auth_error_message', $default_auth_error_message, $field );

        /**
         * Check to see if
         */
        if ( $field instanceof FieldDefinition && (
                isset ( $field->config['isPrivate'] ) ||
                ( ! empty( $field->config['auth'] ) && is_array( $field->config['auth'] ) ) )
        ) {

            /**
             * If the schema for the field is configured to "isPrivate" or has "auth" configured,
             * make sure the user is authenticated before resolving the field
             */
            if ( empty( get_current_user_id() ) ) {
                throw new UserError( $auth_error );
            }

            /**
             * If the user is authenticated, and the field has a custom auth callback configured,
             * execute the callback before continuing resolution
             */
            if ( ! empty( $field->config['auth']['callback'] ) && is_callable( $field->config['auth']['callback'] ) ) {
                return call_user_func( $field->config['auth']['callback'], $field, $field_key, $source, $args, $context, $info, $field_resolver );
            }

            /**
             * If the user is authenticated and the field has "allowedCaps" configured,
             * ensure the user has at least one of the allowedCaps before resolving
             */
            if ( ! empty( $field->config['auth']['allowedCaps'] ) && is_array( $field->config['auth']['allowedCaps'] ) ) {
                $caps = ! empty( wp_get_current_user()->allcaps ) ? wp_get_current_user()->allcaps : [];
                if ( empty( array_intersect( array_keys( $caps ), array_values( $field->config['auth']['allowedCaps'] ) ) ) ) {
                    throw new UserError( $auth_error );
                }
            }

            /**
             * If the user is authenticated and the field has "allowedRoles" configured,
             * ensure the user has at least one of the allowedRoles before resolving
             */
            if ( ! empty( $field->config['auth']['allowedRoles'] ) && is_array( $field->config['auth']['allowedRoles'] ) ) {
                $roles         = ! empty( wp_get_current_user()->roles ) ? wp_get_current_user()->roles : [];
                $allowed_roles = array_values( $field->config['auth']['allowedRoles'] );
                if ( empty( array_intersect( array_values( $roles ), array_values( $allowed_roles ) ) ) ) {
                    throw new UserError( $auth_error );
                }
            }

        }

    }

}
API documentation generated by ApiGen