├── .gitignore ├── wp-graphql-crb.php ├── composer.json ├── README.md ├── src ├── MetaResolver.php ├── Field.php └── Container.php └── composer.lock /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ -------------------------------------------------------------------------------- /wp-graphql-crb.php: -------------------------------------------------------------------------------- 1 | Note: This is a very experimental version, so it is probably shipped with bugs. 10 | 11 | ## Usage 12 | 13 | 1. First you have to install Carbon Fields and WpGraphQL. 14 | 1. Then install this package via packagist: `composer require matepaiva/wp-graphql-crb` 15 | 1. Wrap every Carbon Field container that you want to expose via GraphQL with the static method `WpGraphQLCrb\Container::register`. For example: 16 | 17 | ```php 18 | where('term_taxonomy', '=', 'category') 27 | ->add_fields([ 28 | Field::make('image', 'crb_img') 29 | ->set_value_type('url') 30 | ]) 31 | ); 32 | ``` 33 | 34 | 5. Now the query below will work: 35 | 36 | ```graphql 37 | { 38 | categories { 39 | edges { 40 | node { 41 | id 42 | crb_img 43 | } 44 | } 45 | } 46 | } 47 | ``` 48 | 49 | ## About Theme Options 50 | 51 | Theme options are not part of any structure already known by Wordpress, so it has its own root. Every `theme_options` fields will be displayed in GraphQL as direct children of `crb_ThemeOptions`. Be carefull about name collision. 52 | -------------------------------------------------------------------------------- /src/MetaResolver.php: -------------------------------------------------------------------------------- 1 | getCrbType()) { 14 | case 'rich_text': 15 | return apply_filters('the_content', $value); 16 | 17 | default: 18 | return $value; 19 | } 20 | 21 | } 22 | 23 | public static function getFloat($value, Field $field, Container $container, $args, AppContext $context, ResolveInfo $info) 24 | { 25 | return floatval($value); 26 | } 27 | 28 | public static function getComplex($value, Field $field, Container $container, $args, AppContext $context, ResolveInfo $info) 29 | { 30 | $fields = $field->getFields(); 31 | return array_map(function ($val) use ($fields, $container, $args, $context, $info) { 32 | $complex_item = []; 33 | foreach ($fields as $f) { 34 | $field = Field::create($f); 35 | $name = $field->getBaseName(); 36 | if(!array_key_exists($name, $val)) continue; 37 | $inner_value = $val[$name]; 38 | $resolver_name = $field->getResolverName(); 39 | $complex_item[$name] = call_user_func( 40 | [MetaResolver::class, $resolver_name], 41 | $inner_value, 42 | $field, 43 | $container, 44 | $args, 45 | $context, 46 | $info 47 | ); 48 | } 49 | return $complex_item; 50 | }, $value); 51 | } 52 | 53 | public static function getMediaItem($value, Field $field, Container $container, $args, AppContext $context, ResolveInfo $info) 54 | { 55 | return DataSource::resolve_post_object((int)$value, $context); 56 | } 57 | 58 | public static function getMediaGallery($gallery_ids, Field $field, Container $container, $args, AppContext $context, ResolveInfo $info) 59 | { 60 | return array_map(function ($id) use ($context) { 61 | return DataSource::resolve_post_object($id, $context); 62 | }, $gallery_ids); 63 | } 64 | 65 | public static function getSelect($value, Field $field, Container $container, $args, AppContext $context, ResolveInfo $info) 66 | { 67 | $options = $field->getOptions() ?? []; 68 | 69 | return [ 70 | 'id' => $value, 71 | 'value' => $value ?? null, 72 | 'label' => $options[$value] ?? null, 73 | ]; 74 | } 75 | 76 | public static function getMultiSelect($value, Field $field, Container $container, $args, AppContext $context, ResolveInfo $info) 77 | { 78 | $values = $value ?? []; 79 | $options = $field->getOptions() ?? []; 80 | return array_map(function ($value) use ($options) { 81 | return [ 82 | 'id' => $value, 83 | 'value' => $value, 84 | 'label' => $options[$value] ?? $value, 85 | ]; 86 | }, $values); 87 | } 88 | 89 | public static function getSet($value, Field $field, Container $container, $args, AppContext $context, ResolveInfo $info) 90 | { 91 | $values = $value ?? []; 92 | $options = $field->getOptions() ?? []; 93 | $option_keys = array_keys($options); 94 | 95 | return array_map(function ($key) use ($values, $options) { 96 | return [ 97 | 'id' => $key, 98 | 'value' => in_array($key, $values), 99 | 'label' => $options[$key] ?? $key, 100 | ]; 101 | }, $option_keys); 102 | } 103 | 104 | public static function getAssociation($assocations, Field $field, Container $container, $args, AppContext $context, ResolveInfo $info) 105 | { 106 | return array_map(function ($assocation) use ($context) { 107 | ['type' => $type, 'subtype' => $subtype, 'id' => $id] = $assocation; 108 | 109 | switch ($type) { 110 | case 'post': 111 | $post = DataSource::resolve_post_object($id, $context); 112 | return $post; 113 | 114 | case 'term': 115 | return DataSource::resolve_term_object($id, $context); 116 | 117 | case 'user': 118 | $user = DataSource::resolve_user($id, $context); 119 | return $user; 120 | 121 | case 'comment': 122 | $comment = DataSource::resolve_comment($id, $context); 123 | return $comment; 124 | 125 | default: 126 | return Self::getNull(); 127 | } 128 | }, $assocations); 129 | } 130 | 131 | public static function getNull() 132 | { 133 | return function () { 134 | return null; 135 | }; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/Field.php: -------------------------------------------------------------------------------- 1 | field = $field; 23 | $this->recursiveType = $recursiveType; 24 | } 25 | 26 | static public function create(CrbField $field, String $recursiveType = '') 27 | { 28 | return new Self($field, $recursiveType); 29 | } 30 | 31 | public function getDescription() 32 | { 33 | return $this->field->get_help_text() ?? ''; 34 | } 35 | 36 | public function isCompatible() 37 | { 38 | return !\in_array($this->getCrbType(), Field::$blacklisted_fields); 39 | } 40 | 41 | public function getType() 42 | { 43 | switch ($this->getCrbType()) { 44 | 45 | case 'text': 46 | $type = $this->getTextType(); 47 | break; 48 | 49 | case 'radio': 50 | case 'select': 51 | $type = 'Crb_Select'; 52 | break; 53 | 54 | case 'image': 55 | $type = 'mediaItem'; 56 | break; 57 | 58 | case 'multiselect': 59 | $type = ['list_of' => 'Crb_Select']; 60 | break; 61 | 62 | case 'set': 63 | $type = ['list_of' => 'Crb_Set']; 64 | break; 65 | 66 | case 'media_gallery': 67 | $type = ['list_of' => 'mediaItem']; 68 | break; 69 | 70 | case 'association': 71 | $type = ['list_of' => $this->getTypeFromAssociation()]; 72 | break; 73 | 74 | case 'complex': 75 | $type = ['list_of' => $this->getTypeFromComplex()]; 76 | break; 77 | 78 | case 'checkbox': 79 | $type = 'Boolean'; 80 | break; 81 | 82 | default: 83 | $type = 'String'; 84 | } 85 | 86 | return apply_filters('wp_graphql_crb_type', $type, $this->getCrbType()); 87 | } 88 | 89 | public function getBaseName() 90 | { 91 | return $this->field->get_base_name(); 92 | } 93 | 94 | public function getOptions() 95 | { 96 | return $this->field->get_options(); 97 | } 98 | 99 | public function getResolver() 100 | { 101 | return [MetaResolver::class, $this->getResolverName()]; 102 | } 103 | 104 | public function getFields() { 105 | return $this->field->get_fields(); 106 | } 107 | 108 | private function getTextType() 109 | { 110 | $attributes = $this->field->get_attributes(); 111 | 112 | $html_type = $attributes['type'] ?? 'text'; 113 | 114 | switch ($html_type) { 115 | case 'number': 116 | return 'Float'; 117 | 118 | default: 119 | return 'String'; 120 | } 121 | } 122 | 123 | public function getCrbType() 124 | { 125 | return $this->field->get_type(); 126 | } 127 | 128 | public function getResolverName() 129 | { 130 | if ($this->getCrbType() === 'association') { 131 | return 'getAssociation'; 132 | } 133 | 134 | if ($this->getCrbType() === 'complex') { 135 | return 'getComplex'; 136 | } 137 | 138 | $type = $this->getType(); 139 | 140 | if (is_array($type)) { 141 | $type = json_encode($type); 142 | } 143 | 144 | switch ($type) { 145 | case 'String': 146 | case 'Boolean': 147 | $resolver_name = 'getScalar'; 148 | break; 149 | 150 | case 'Float': 151 | $resolver_name = 'getFloat'; 152 | break; 153 | 154 | case 'mediaItem': 155 | $resolver_name = 'getMediaItem'; 156 | break; 157 | 158 | case '{"list_of":"mediaItem"}': 159 | $resolver_name = 'getMediaGallery'; 160 | break; 161 | 162 | case '{"list_of":"Crb_Set"}': 163 | $resolver_name = 'getSet'; 164 | break; 165 | 166 | case 'Crb_Select': 167 | $resolver_name = 'getSelect'; 168 | break; 169 | 170 | case '{"list_of":"Crb_Select"}': 171 | $resolver_name = 'getMultiSelect'; 172 | break; 173 | 174 | default: 175 | $resolver_name = 'getNull'; 176 | } 177 | 178 | return apply_filters('wp_graphql_crb_resolver_name', $resolver_name, $type); 179 | } 180 | 181 | private function getTypeFromAssociation() 182 | { 183 | $types = $this->field->get_types(); 184 | 185 | if (count($types) === 1) { 186 | [$type] = $types; 187 | 188 | return $this->getGraphQLTypeFromAssociationType($type); 189 | } 190 | 191 | $type_names = array_map([$this, 'getGraphQLTypeFromAssociationType'], $types); 192 | $union_name = 'Union_' . $this->field->get_base_name(); 193 | 194 | register_graphql_union_type($union_name, [ 195 | 'typeNames' => $type_names, 196 | 'resolveType' => function ($object) { 197 | if ($object instanceof Post) { 198 | $graphql_single_name = \get_post_type_object($object->post_type)->graphql_single_name; 199 | 200 | return ucfirst($graphql_single_name); 201 | } 202 | 203 | if ($object instanceof Term) { 204 | $taxonomy_name = \get_taxonomy($object->taxonomyName)->graphql_single_name; 205 | 206 | return ucfirst($taxonomy_name); 207 | } 208 | 209 | if ($object instanceof Comment) { 210 | return 'Comment'; 211 | } 212 | 213 | if ($object instanceof User) { 214 | return 'User'; 215 | } 216 | 217 | return ''; 218 | } 219 | ]); 220 | 221 | return $union_name; 222 | } 223 | 224 | private function getTypeFromComplex() 225 | { 226 | $complex_prefix = $this->recursiveType ? $this->recursiveType : 'Complex'; 227 | $type = $complex_prefix . '_' . $this->getBaseName(); 228 | 229 | $fields = array_reduce($this->field->get_fields(), function($fields, $f) use ($type) { 230 | $field = Field::create($f, $type); 231 | 232 | $fields[$field->getBaseName()] = [ 233 | 'type' => $field->getType(), 234 | 'description' => $field->getDescription() 235 | ]; 236 | 237 | return $fields; 238 | }, []); 239 | 240 | register_graphql_object_type($type, [ 241 | 'description' => $this->getDescription(), 242 | 'fields' => $fields, 243 | ]); 244 | 245 | return $type; 246 | } 247 | 248 | private function getGraphQLTypeFromAssociationType($type) 249 | { 250 | switch ($type['type']) { 251 | case 'post': 252 | return \get_post_type_object($type['post_type'])->graphql_single_name; 253 | 254 | case 'term': 255 | return \get_taxonomy($type['taxonomy'])->graphql_single_name; 256 | 257 | case 'user': 258 | return 'user'; 259 | 260 | case 'comment': 261 | return 'comment'; 262 | 263 | default: 264 | return $type['type']; 265 | } 266 | } 267 | } 268 | -------------------------------------------------------------------------------- /src/Container.php: -------------------------------------------------------------------------------- 1 | container = $container; 30 | $this->fields = $this->getFields(); 31 | \add_action('graphql_register_types', [$this, 'graphqlRegisterTypes']); 32 | } 33 | 34 | static public function register(CrbContainer $container) 35 | { 36 | return new Self($container); 37 | } 38 | 39 | private function registerField(Field $field) 40 | { 41 | $roots = $this->container->type === 'theme_options' ? ['Crb_ThemeOptions'] : $this->getGraphQLRoot(); 42 | $field_name = $field->getBaseName(); 43 | $options = [ 44 | 'type' => $field->getType($field), 45 | 'description' => $field->getDescription($field), 46 | 'resolve' => $this->getGraphQLResolver($field), 47 | ]; 48 | 49 | foreach ($roots as $root) { 50 | register_graphql_field($root, $field_name, $options); 51 | } 52 | } 53 | 54 | public function graphqlRegisterTypes() 55 | { 56 | if (Container::$is_first_time) { 57 | Container::$is_first_time = false; 58 | Container::registerStaticObjectTypes(); 59 | } 60 | 61 | if ($this->container->type === 'theme_options' && Container::$is_first_time_theme_options) { 62 | Container::$is_first_time_theme_options = false; 63 | Container::registerStaticThemeOptionObjectTypes(); 64 | } 65 | 66 | $this->registerFields(); 67 | } 68 | 69 | private function registerFields() 70 | { 71 | foreach ($this->fields as $field) { 72 | $this->registerField($field); 73 | } 74 | } 75 | 76 | static function registerStaticThemeOptionObjectTypes() 77 | { 78 | register_graphql_object_type( 79 | 'Crb_ThemeOptions', [ 80 | 'description' => \__("All the Carbon Field Theme Options", 'app'), 81 | 'fields' => [], 82 | ] 83 | ); 84 | 85 | register_graphql_field( 86 | 'RootQuery', 87 | 'crb_ThemeOptions', 88 | [ 89 | 'type' => 'Crb_ThemeOptions', 90 | 'resolve' => function ($src) { 91 | return []; 92 | } 93 | ] 94 | ); 95 | } 96 | 97 | static function registerStaticObjectTypes() 98 | { 99 | register_graphql_object_type('Crb_Select', [ 100 | 'description' => \__("The selected option/radio", 'app'), 101 | 'fields' => [ 102 | 'label' => [ 103 | 'type' => 'String', 104 | 'description' => \__('The label of the option', 'app'), 105 | ], 106 | 'value' => [ 107 | 'type' => 'String', 108 | 'description' => \__('The value of the option', 'app'), 109 | ], 110 | 'id' => [ 111 | 'type' => 'String', 112 | 'description' => \__('The value of the option', 'app'), 113 | ], 114 | ], 115 | ]); 116 | 117 | register_graphql_object_type('Crb_Set', [ 118 | 'description' => \__("The option/radio", 'app'), 119 | 'fields' => [ 120 | 'label' => [ 121 | 'type' => 'String', 122 | 'description' => \__('The label of the option', 'app'), 123 | ], 124 | 'value' => [ 125 | 'type' => 'Boolean', 126 | 'description' => \__('The value indicates if the option is selected or not', 'app'), 127 | ], 128 | 'id' => [ 129 | 'type' => 'String', 130 | 'description' => \__('The id of the option', 'app'), 131 | ], 132 | ], 133 | ]); 134 | } 135 | 136 | public function getGraphQLResolver(Field $field) 137 | { 138 | $resolver = $this->getResolver($field); 139 | 140 | $field_resolver = $field->getResolver(); 141 | 142 | return $resolver($field_resolver); 143 | } 144 | 145 | private function getResolver(Field $field) 146 | { 147 | return function ($cb) use ($field) { 148 | switch ($this->container->type) { 149 | case 'post_meta': 150 | return function (Post $post, $args, AppContext $context, ResolveInfo $info) use ($field, $cb) { 151 | $value = carbon_get_post_meta($post->ID, $field->getBaseName()); 152 | return $cb($value, $field, $this, $args, $context, $info); 153 | }; 154 | 155 | case 'term_meta': 156 | return function (Term $term, $args, AppContext $context, ResolveInfo $info) use ($field, $cb) { 157 | $value = carbon_get_term_meta($term->term_id, $field->getBaseName()); 158 | return $cb($value, $field, $this, $args, $context, $info); 159 | }; 160 | 161 | case 'user_meta': 162 | return function (User $user, $args, AppContext $context, ResolveInfo $info) use ($field, $cb) { 163 | $value = carbon_get_user_meta($user->userId, $field->getBaseName()); 164 | return $cb($value, $field, $this, $args, $context, $info); 165 | }; 166 | 167 | case 'comment_meta': 168 | return function (Comment $comment, $args, AppContext $context, ResolveInfo $info) use ($field, $cb) { 169 | $value = carbon_get_comment_meta($comment->databaseId, $field->getBaseName()); 170 | return $cb($value, $field, $this, $args, $context, $info); 171 | }; 172 | 173 | case 'theme_options': 174 | return function ($_, $args, AppContext $context, ResolveInfo $info) use ($field, $cb) { 175 | $value = carbon_get_theme_option($field->getBaseName()); 176 | return $cb($value, $field, $this, $args, $context, $info); 177 | }; 178 | 179 | default: 180 | return function () use ($cb) { 181 | return $cb(); 182 | }; 183 | } 184 | }; 185 | } 186 | 187 | private function getGraphQLRoot() 188 | { 189 | $context = $this->container->type; 190 | $type_callable = array(Decorator::class, "get_{$context}_container_settings"); 191 | 192 | if (!is_callable($type_callable)) { 193 | return []; 194 | } 195 | 196 | $types = call_user_func($type_callable, $this->container); 197 | 198 | if (!is_array($types)) { 199 | $types = [$types]; 200 | } 201 | 202 | $roots = array_reduce($types, function ($graphql_types, $type) { 203 | switch ($this->container->type) { 204 | case 'post_meta': 205 | $graphql_type = $this->getGraphQLPostTypeRoot($type); 206 | break; 207 | 208 | case 'term_meta': 209 | $graphql_type = $this->getGraphQLTermTypeRoot($type); 210 | break; 211 | 212 | case 'user_meta': 213 | $graphql_type = 'User'; 214 | break; 215 | 216 | case 'comment_meta': 217 | $graphql_type = 'Comment'; 218 | break; 219 | 220 | default: 221 | $graphql_type = 'Post'; 222 | } 223 | 224 | if(isset($graphql_type)) { 225 | $graphql_types[] = $graphql_type; 226 | } 227 | 228 | return $graphql_types; 229 | }, []); 230 | 231 | return $roots; 232 | } 233 | 234 | private function getGraphQLPostTypeRoot(String $type) 235 | { 236 | $post_type_object = \get_post_type_object($type); 237 | 238 | $graphql_type = isset($post_type_object->graphql_single_name) ? $post_type_object->graphql_single_name : null; 239 | 240 | return $graphql_type; 241 | } 242 | 243 | private function getGraphQLTermTypeRoot(String $type) 244 | { 245 | $taxonomy_object = \get_taxonomy($type); 246 | 247 | $graphql_type = isset($taxonomy_object->graphql_single_name) ? $taxonomy_object->graphql_single_name : null; 248 | 249 | return $graphql_type; 250 | } 251 | 252 | private function getFields() 253 | { 254 | $graphql_fields = array_map(function ($field) { 255 | return Field::create($field); 256 | }, $this->container->get_fields()); 257 | 258 | return array_filter($graphql_fields, function (Field $field) { 259 | return $field->isCompatible(); 260 | }); 261 | } 262 | } 263 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "55a97d87f6adf6fe35b8f945d4503fd2", 8 | "packages": [ 9 | { 10 | "name": "htmlburger/carbon-fields", 11 | "version": "dev-exopse_registered_fields", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/matepaiva/carbon-fields.git", 15 | "reference": "401988372806c54f4b0af6ec937113e88e77c68b" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/matepaiva/carbon-fields/zipball/401988372806c54f4b0af6ec937113e88e77c68b", 20 | "reference": "401988372806c54f4b0af6ec937113e88e77c68b", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "php": ">=5.3" 25 | }, 26 | "require-dev": { 27 | "mockery/mockery": "^0.9.7", 28 | "phpunit/phpunit": "~4.8" 29 | }, 30 | "type": "library", 31 | "autoload": { 32 | "psr-4": { 33 | "Carbon_Fields\\": "core/" 34 | } 35 | }, 36 | "license": [ 37 | "GPL-2.0-only" 38 | ], 39 | "authors": [ 40 | { 41 | "name": "htmlBurger", 42 | "email": "wordpress@htmlburger.com", 43 | "homepage": "https://htmlburger.com/", 44 | "role": "Developer" 45 | }, 46 | { 47 | "name": "Miroslav Mitev", 48 | "email": "mmitev.2create@gmail.com", 49 | "role": "Developer" 50 | }, 51 | { 52 | "name": "Atanas Angelov", 53 | "email": "atanas.angelov.dev@gmail.com", 54 | "role": "Developer" 55 | }, 56 | { 57 | "name": "Georgi Stoyanov", 58 | "email": "stoyanov.gs@gmail.com", 59 | "role": "Developer" 60 | }, 61 | { 62 | "name": "Plamen Kostadinov", 63 | "email": "pkostadinov.2create@gmail.com", 64 | "homepage": "http://plasmen.info/", 65 | "role": "Developer" 66 | }, 67 | { 68 | "name": "Stanimir Panchev", 69 | "email": "Stan4omir@gmail.com", 70 | "role": "Developer" 71 | }, 72 | { 73 | "name": "Marin Atanasov", 74 | "email": "contact@marinatanasov.com", 75 | "homepage": "http://marinatanasov.com/", 76 | "role": "Developer" 77 | }, 78 | { 79 | "name": "Siyan Panayotov", 80 | "homepage": "http://siyanpanayotov.com/", 81 | "role": "Developer" 82 | }, 83 | { 84 | "name": "Peter Petrov", 85 | "email": "peter.petrov89@gmail.com", 86 | "role": "Developer" 87 | }, 88 | { 89 | "name": "Stanimir Stoyanov", 90 | "email": "stanimir.k.stoyanov@gmail.com", 91 | "role": "Developer" 92 | }, 93 | { 94 | "name": "Kaloyan Ivanov", 95 | "email": "kaloyanxivanov@gmail.com", 96 | "homepage": "http://vilepixels.com/", 97 | "role": "Developer" 98 | }, 99 | { 100 | "name": "Georgi Popov", 101 | "homepage": "http://magadanski.com/", 102 | "role": "Developer" 103 | }, 104 | { 105 | "name": "German Velchev", 106 | "email": "germozy@gmail.com", 107 | "role": "Developer" 108 | }, 109 | { 110 | "name": "Rashko Petrov", 111 | "email": "brutalenemy666@gmail.com", 112 | "homepage": "http://errorfactory.com/", 113 | "role": "Developer" 114 | }, 115 | { 116 | "name": "Alexander Panayotov", 117 | "email": "alexander.panayotov@gmail.com", 118 | "homepage": "http://alexanderpanayotov.com/", 119 | "role": "Developer" 120 | }, 121 | { 122 | "name": "Viktor Vasilev", 123 | "email": "liberalcho@gmail.com", 124 | "role": "Developer" 125 | }, 126 | { 127 | "name": "Georgi Georgiev", 128 | "email": "george.georgiev96@gmail.com", 129 | "role": "Developer" 130 | }, 131 | { 132 | "name": "Atanas Vasilev", 133 | "email": "atanasvasilev91@gmail.com", 134 | "role": "Developer" 135 | } 136 | ], 137 | "description": "WordPress developer-friendly custom fields for post types, taxonomy terms, users, comments, widgets, options and more.", 138 | "homepage": "http://carbonfields.net/", 139 | "support": { 140 | "source": "https://github.com/htmlburger/carbon-fields", 141 | "issues": "https://github.com/htmlburger/carbon-fields/issues", 142 | "docs": "http://carbonfields.net/docs/", 143 | "email": "wordpress@htmlburger.com" 144 | }, 145 | "time": "2019-12-23T11:08:25+00:00" 146 | }, 147 | { 148 | "name": "ivome/graphql-relay-php", 149 | "version": "v0.3.1", 150 | "source": { 151 | "type": "git", 152 | "url": "https://github.com/ivome/graphql-relay-php.git", 153 | "reference": "bc5f8aae9fd72ca16decce3892ec4311e9742a93" 154 | }, 155 | "dist": { 156 | "type": "zip", 157 | "url": "https://api.github.com/repos/ivome/graphql-relay-php/zipball/bc5f8aae9fd72ca16decce3892ec4311e9742a93", 158 | "reference": "bc5f8aae9fd72ca16decce3892ec4311e9742a93", 159 | "shasum": "" 160 | }, 161 | "require": { 162 | "php": ">=5.4,<8.0-DEV", 163 | "webonyx/graphql-php": ">=0.7.0" 164 | }, 165 | "require-dev": { 166 | "phpunit/phpunit": "^4.8", 167 | "satooshi/php-coveralls": "~1.0" 168 | }, 169 | "type": "library", 170 | "autoload": { 171 | "classmap": [ 172 | "src/" 173 | ] 174 | }, 175 | "notification-url": "https://packagist.org/downloads/", 176 | "license": [ 177 | "BSD" 178 | ], 179 | "description": "A PHP port of GraphQL Relay reference implementation", 180 | "homepage": "https://github.com/ivome/graphql-relay-php", 181 | "keywords": [ 182 | "Relay", 183 | "api", 184 | "graphql" 185 | ], 186 | "time": "2016-10-29T23:29:29+00:00" 187 | }, 188 | { 189 | "name": "webonyx/graphql-php", 190 | "version": "v0.12.6", 191 | "source": { 192 | "type": "git", 193 | "url": "https://github.com/webonyx/graphql-php.git", 194 | "reference": "4c545e5ec4fc37f6eb36c19f5a0e7feaf5979c95" 195 | }, 196 | "dist": { 197 | "type": "zip", 198 | "url": "https://api.github.com/repos/webonyx/graphql-php/zipball/4c545e5ec4fc37f6eb36c19f5a0e7feaf5979c95", 199 | "reference": "4c545e5ec4fc37f6eb36c19f5a0e7feaf5979c95", 200 | "shasum": "" 201 | }, 202 | "require": { 203 | "ext-mbstring": "*", 204 | "php": ">=5.6" 205 | }, 206 | "require-dev": { 207 | "phpunit/phpunit": "^4.8", 208 | "psr/http-message": "^1.0", 209 | "react/promise": "2.*" 210 | }, 211 | "suggest": { 212 | "psr/http-message": "To use standard GraphQL server", 213 | "react/promise": "To leverage async resolving on React PHP platform" 214 | }, 215 | "type": "library", 216 | "autoload": { 217 | "psr-4": { 218 | "GraphQL\\": "src/" 219 | } 220 | }, 221 | "notification-url": "https://packagist.org/downloads/", 222 | "license": [ 223 | "MIT" 224 | ], 225 | "description": "A PHP port of GraphQL reference implementation", 226 | "homepage": "https://github.com/webonyx/graphql-php", 227 | "keywords": [ 228 | "api", 229 | "graphql" 230 | ], 231 | "time": "2018-09-02T14:59:54+00:00" 232 | }, 233 | { 234 | "name": "wp-graphql/wp-graphql", 235 | "version": "v0.5.1", 236 | "source": { 237 | "type": "git", 238 | "url": "https://github.com/wp-graphql/wp-graphql.git", 239 | "reference": "c6fbc3bdbce610cdc5996cd2023b37606d09de0c" 240 | }, 241 | "dist": { 242 | "type": "zip", 243 | "url": "https://api.github.com/repos/wp-graphql/wp-graphql/zipball/c6fbc3bdbce610cdc5996cd2023b37606d09de0c", 244 | "reference": "c6fbc3bdbce610cdc5996cd2023b37606d09de0c", 245 | "shasum": "" 246 | }, 247 | "require": { 248 | "ivome/graphql-relay-php": "^0.3.1", 249 | "webonyx/graphql-php": "0.12.6" 250 | }, 251 | "require-dev": { 252 | "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0", 253 | "lucatume/wp-browser": "^2.2.", 254 | "phpcompatibility/phpcompatibility-wp": "^2.0", 255 | "wp-coding-standards/wpcs": "^2.1" 256 | }, 257 | "type": "wordpress-plugin", 258 | "autoload": { 259 | "psr-4": { 260 | "WPGraphQL\\": "src/" 261 | }, 262 | "classmap": [ 263 | "src/" 264 | ] 265 | }, 266 | "notification-url": "https://packagist.org/downloads/", 267 | "license": [ 268 | "GPL-3.0-or-later" 269 | ], 270 | "authors": [ 271 | { 272 | "name": "Jason Bahl", 273 | "email": "jasonbahl@mac.com" 274 | }, 275 | { 276 | "name": "Edwin Cromley" 277 | }, 278 | { 279 | "name": "Ryan Kanner" 280 | }, 281 | { 282 | "name": "Hughie Devore" 283 | }, 284 | { 285 | "name": "Chris Zarate" 286 | } 287 | ], 288 | "description": "GraphQL API for WordPress", 289 | "time": "2019-12-13T17:18:57+00:00" 290 | } 291 | ], 292 | "packages-dev": [], 293 | "aliases": [], 294 | "minimum-stability": "stable", 295 | "stability-flags": { 296 | "htmlburger/carbon-fields": 20 297 | }, 298 | "prefer-stable": false, 299 | "prefer-lowest": false, 300 | "platform": [], 301 | "platform-dev": [] 302 | } 303 | --------------------------------------------------------------------------------