From 22b6a4024760b46b4fa4c31c8b42b691e8be3fc1 Mon Sep 17 00:00:00 2001 From: Mark Kelnar <749603+markkelnar@users.noreply.github.com> Date: Tue, 28 Jun 2022 14:13:03 -0500 Subject: [PATCH 1/9] Move max-age to cache tab, settings --- src/Admin/Settings.php | 48 +++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/Admin/Settings.php b/src/Admin/Settings.php index bd7a24bb..c328d0cc 100644 --- a/src/Admin/Settings.php +++ b/src/Admin/Settings.php @@ -43,24 +43,8 @@ function () { register_graphql_settings_section( 'graphql_persisted_queries_section', [ - 'title' => __( 'Network Cache', 'wp-graphql-labs' ), - 'desc' => __( 'These settings apply to GraphQL queries coming over HTTP requests.', 'wp-graphql-labs' ), - ] - ); - - register_graphql_settings_field( - 'graphql_persisted_queries_section', - [ - 'name' => 'global_max_age', - 'label' => __( 'Access-Control-Max-Age Header', 'wp-graphql-labs' ), - 'desc' => __( 'Global Max-Age HTTP header. Integer value, greater or equal to zero.', 'wp-graphql-labs' ), - 'type' => 'number', - 'sanitize_callback' => function ( $value ) { - if ( $value < 0 || ! is_numeric( $value ) ) { - return 0; - } - return intval( $value ); - }, + 'title' => __( 'Saved Queries', 'wp-graphql-labs' ), + 'desc' => __( 'Saved/Persisted GraphQL Queries', 'wp-graphql-labs' ), ] ); @@ -110,8 +94,24 @@ function () { register_graphql_settings_section( 'graphql_cache_section', [ - 'title' => __( 'Object Cache', 'wp-graphql-labs' ), - 'desc' => __( 'Use local object or transient cache to save entire GraphQL query results, for improved speed and performance.', 'wp-graphql-labs' ), + 'title' => __( 'Cache', 'wp-graphql-labs' ), + 'desc' => __( 'Caching and other settings related to improved performance of GraphQL queries.', 'wp-graphql-labs' ), + ] + ); + + register_graphql_settings_field( + 'graphql_cache_section', + [ + 'name' => 'global_max_age', + 'label' => __( 'Access-Control-Max-Age Header', 'wp-graphql-labs' ), + 'desc' => __( 'Global Max-Age HTTP header. Integer value, greater or equal to zero.', 'wp-graphql-labs' ), + 'type' => 'number', + 'sanitize_callback' => function ( $value ) { + if ( $value < 0 || ! is_numeric( $value ) ) { + return 0; + } + return intval( $value ); + }, ] ); @@ -119,8 +119,8 @@ function () { 'graphql_cache_section', [ 'name' => 'cache_toggle', - 'label' => __( 'GraphQL Object Cache', 'wp-graphql-labs' ), - 'desc' => __( 'Store and return results of GraphQL Queries in the Object cache until they have expired (see below) or a related action has evicted the cached response.', 'wp-graphql-labs' ), + 'label' => __( 'Use Object Cache', 'wp-graphql-labs' ), + 'desc' => __( 'Use local object or transient cache to save entire GraphQL query results, for improved speed and performance. Store and return results of GraphQL Queries in the Object cache until they have expired (see below) or a related action has evicted the cached response.', 'wp-graphql-labs' ), 'type' => 'checkbox', 'default' => 'off', ] @@ -147,8 +147,8 @@ function () { 'graphql_cache_section', [ 'name' => 'purge_all', - 'label' => __( 'Purge GraphQL Object Cache', 'wp-graphql-labs' ), - 'desc' => __( 'Select this box and click the save button to purge all responses stored in the GraphQL Object Cache.', 'wp-graphql-labs' ), + 'label' => __( 'Purge Now!', 'wp-graphql-labs' ), + 'desc' => __( 'Purge GraphQL Cache. Select this box and click the save button to purge all responses stored in the GraphQL Cache.', 'wp-graphql-labs' ), 'type' => 'checkbox', 'default' => 'off', 'sanitize_callback' => function ( $value ) { From 43e9fca0def1da77e73463e00c5b55fe06de6fa0 Mon Sep 17 00:00:00 2001 From: Mark Kelnar <749603+markkelnar@users.noreply.github.com> Date: Tue, 28 Jun 2022 15:07:42 -0500 Subject: [PATCH 2/9] Fix global_ttl setting section and tests --- composer.lock | 94 ++++++++++---------- src/Document/MaxAge.php | 2 +- tests/functional/AdminSettingsMaxAgeCest.php | 10 +-- tests/functional/DocumentMaxAgeCest.php | 14 +-- tests/functional/LookupCest.php | 2 - 5 files changed, 60 insertions(+), 62 deletions(-) diff --git a/composer.lock b/composer.lock index b2e0b97c..eb1d8c1b 100644 --- a/composer.lock +++ b/composer.lock @@ -1492,16 +1492,16 @@ }, { "name": "illuminate/collections", - "version": "v9.18.0", + "version": "v9.19.0", "source": { "type": "git", "url": "https://github.com/illuminate/collections.git", - "reference": "239c9274b8008fb9532ada0899365d1e182f8f9d" + "reference": "253cfce2bf469c340d2268bfbc31d4ad446a1fa7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/collections/zipball/239c9274b8008fb9532ada0899365d1e182f8f9d", - "reference": "239c9274b8008fb9532ada0899365d1e182f8f9d", + "url": "https://api.github.com/repos/illuminate/collections/zipball/253cfce2bf469c340d2268bfbc31d4ad446a1fa7", + "reference": "253cfce2bf469c340d2268bfbc31d4ad446a1fa7", "shasum": "" }, "require": { @@ -1543,11 +1543,11 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2022-06-19T21:41:21+00:00" + "time": "2022-06-28T14:33:19+00:00" }, { "name": "illuminate/conditionable", - "version": "v9.18.0", + "version": "v9.19.0", "source": { "type": "git", "url": "https://github.com/illuminate/conditionable.git", @@ -1593,7 +1593,7 @@ }, { "name": "illuminate/contracts", - "version": "v9.18.0", + "version": "v9.19.0", "source": { "type": "git", "url": "https://github.com/illuminate/contracts.git", @@ -1641,7 +1641,7 @@ }, { "name": "illuminate/macroable", - "version": "v9.18.0", + "version": "v9.19.0", "source": { "type": "git", "url": "https://github.com/illuminate/macroable.git", @@ -1687,16 +1687,16 @@ }, { "name": "illuminate/support", - "version": "v9.18.0", + "version": "v9.19.0", "source": { "type": "git", "url": "https://github.com/illuminate/support.git", - "reference": "07b158210af5aaca51049c8e87606046ae6573e2" + "reference": "350d65d043cd81ef84e8f5967d8935e8fa52c055" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/support/zipball/07b158210af5aaca51049c8e87606046ae6573e2", - "reference": "07b158210af5aaca51049c8e87606046ae6573e2", + "url": "https://api.github.com/repos/illuminate/support/zipball/350d65d043cd81ef84e8f5967d8935e8fa52c055", + "reference": "350d65d043cd81ef84e8f5967d8935e8fa52c055", "shasum": "" }, "require": { @@ -1752,7 +1752,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2022-06-21T14:08:45+00:00" + "time": "2022-06-28T14:33:19+00:00" }, { "name": "justinrainbow/json-schema", @@ -4874,16 +4874,16 @@ }, { "name": "symfony/console", - "version": "v5.4.9", + "version": "v5.4.10", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "829d5d1bf60b2efeb0887b7436873becc71a45eb" + "reference": "4d671ab4ddac94ee439ea73649c69d9d200b5000" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/829d5d1bf60b2efeb0887b7436873becc71a45eb", - "reference": "829d5d1bf60b2efeb0887b7436873becc71a45eb", + "url": "https://api.github.com/repos/symfony/console/zipball/4d671ab4ddac94ee439ea73649c69d9d200b5000", + "reference": "4d671ab4ddac94ee439ea73649c69d9d200b5000", "shasum": "" }, "require": { @@ -4953,7 +4953,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.9" + "source": "https://github.com/symfony/console/tree/v5.4.10" }, "funding": [ { @@ -4969,7 +4969,7 @@ "type": "tidelift" } ], - "time": "2022-05-18T06:17:34+00:00" + "time": "2022-06-26T13:00:04+00:00" }, { "name": "symfony/css-selector", @@ -5039,7 +5039,7 @@ }, { "name": "symfony/deprecation-contracts", - "version": "v3.0.1", + "version": "v3.0.2", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", @@ -5086,7 +5086,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.0.1" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.0.2" }, "funding": [ { @@ -5266,7 +5266,7 @@ }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.0.1", + "version": "v3.0.2", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", @@ -5325,7 +5325,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.0.1" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.0.2" }, "funding": [ { @@ -5961,16 +5961,16 @@ }, { "name": "symfony/service-contracts", - "version": "v3.0.1", + "version": "v3.0.2", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "e517458f278c2131ca9f262f8fbaf01410f2c65c" + "reference": "d78d39c1599bd1188b8e26bb341da52c3c6d8a66" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e517458f278c2131ca9f262f8fbaf01410f2c65c", - "reference": "e517458f278c2131ca9f262f8fbaf01410f2c65c", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d78d39c1599bd1188b8e26bb341da52c3c6d8a66", + "reference": "d78d39c1599bd1188b8e26bb341da52c3c6d8a66", "shasum": "" }, "require": { @@ -6023,7 +6023,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.0.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.0.2" }, "funding": [ { @@ -6039,20 +6039,20 @@ "type": "tidelift" } ], - "time": "2022-03-13T20:10:05+00:00" + "time": "2022-05-30T19:17:58+00:00" }, { "name": "symfony/string", - "version": "v6.0.9", + "version": "v6.0.10", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "df9f03d595aa2d446498ba92fe803a519b2c43cc" + "reference": "1b3adf02a0fc814bd9118d7fd68a097a599ebc27" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/df9f03d595aa2d446498ba92fe803a519b2c43cc", - "reference": "df9f03d595aa2d446498ba92fe803a519b2c43cc", + "url": "https://api.github.com/repos/symfony/string/zipball/1b3adf02a0fc814bd9118d7fd68a097a599ebc27", + "reference": "1b3adf02a0fc814bd9118d7fd68a097a599ebc27", "shasum": "" }, "require": { @@ -6108,7 +6108,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.0.9" + "source": "https://github.com/symfony/string/tree/v6.0.10" }, "funding": [ { @@ -6124,7 +6124,7 @@ "type": "tidelift" } ], - "time": "2022-04-22T08:18:02+00:00" + "time": "2022-06-26T16:34:50+00:00" }, { "name": "symfony/translation", @@ -6223,16 +6223,16 @@ }, { "name": "symfony/translation-contracts", - "version": "v3.0.1", + "version": "v3.0.2", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "c4183fc3ef0f0510893cbeedc7718fb5cafc9ac9" + "reference": "acbfbb274e730e5a0236f619b6168d9dedb3e282" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/c4183fc3ef0f0510893cbeedc7718fb5cafc9ac9", - "reference": "c4183fc3ef0f0510893cbeedc7718fb5cafc9ac9", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/acbfbb274e730e5a0236f619b6168d9dedb3e282", + "reference": "acbfbb274e730e5a0236f619b6168d9dedb3e282", "shasum": "" }, "require": { @@ -6281,7 +6281,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.0.1" + "source": "https://github.com/symfony/translation-contracts/tree/v3.0.2" }, "funding": [ { @@ -6297,20 +6297,20 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:55:41+00:00" + "time": "2022-06-27T17:10:44+00:00" }, { "name": "symfony/yaml", - "version": "v5.4.3", + "version": "v5.4.10", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "e80f87d2c9495966768310fc531b487ce64237a2" + "reference": "04e42926429d9e8b39c174387ab990bf7817f7a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/e80f87d2c9495966768310fc531b487ce64237a2", - "reference": "e80f87d2c9495966768310fc531b487ce64237a2", + "url": "https://api.github.com/repos/symfony/yaml/zipball/04e42926429d9e8b39c174387ab990bf7817f7a2", + "reference": "04e42926429d9e8b39c174387ab990bf7817f7a2", "shasum": "" }, "require": { @@ -6356,7 +6356,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v5.4.3" + "source": "https://github.com/symfony/yaml/tree/v5.4.10" }, "funding": [ { @@ -6372,7 +6372,7 @@ "type": "tidelift" } ], - "time": "2022-01-26T16:32:32+00:00" + "time": "2022-06-20T11:50:59+00:00" }, { "name": "theseer/tokenizer", diff --git a/src/Document/MaxAge.php b/src/Document/MaxAge.php index ad9bbf54..a4fe900a 100644 --- a/src/Document/MaxAge.php +++ b/src/Document/MaxAge.php @@ -163,7 +163,7 @@ public function http_headers_cb( $headers ) { if ( null === $age ) { // If not, use a global max-age setting if set. - $age = get_graphql_setting( 'global_max_age', null, 'graphql_persisted_queries_section' ); + $age = get_graphql_setting( 'global_max_age', null, 'graphql_cache_section' ); } // Access-Control-Max-Age header should be zero or positive integer, no decimals. diff --git a/tests/functional/AdminSettingsMaxAgeCest.php b/tests/functional/AdminSettingsMaxAgeCest.php index 6bd0c380..441284cf 100644 --- a/tests/functional/AdminSettingsMaxAgeCest.php +++ b/tests/functional/AdminSettingsMaxAgeCest.php @@ -7,19 +7,19 @@ class AdminSettingsMaxAgeCest { public function _after( FunctionalTester $I ) { - $I->dontHaveOptionInDatabase( 'graphql_persisted_queries_section' ); + $I->dontHaveOptionInDatabase( 'graphql_cache_section' ); } public function saveMaxAgeSettingsTest( FunctionalTester $I ) { $I->loginAsAdmin(); - $I->amOnPage('/wp-admin/admin.php?page=graphql-settings#graphql_persisted_queries_section'); - $I->seeInField(['name' => 'graphql_persisted_queries_section[global_max_age]'], null); - $I->fillField(['name' => 'graphql_persisted_queries_section[global_max_age]'], '30'); + $I->amOnPage('/wp-admin/admin.php?page=graphql-settings#graphql_cache_section'); + $I->seeInField(['name' => 'graphql_cache_section[global_max_age]'], null); + $I->fillField(['name' => 'graphql_cache_section[global_max_age]'], '30'); // Save and see the selection after form submit $I->click('Save Changes'); - $I->seeInField(['name' => 'graphql_persisted_queries_section[global_max_age]'], '30'); + $I->seeInField(['name' => 'graphql_cache_section[global_max_age]'], '30'); } } diff --git a/tests/functional/DocumentMaxAgeCest.php b/tests/functional/DocumentMaxAgeCest.php index 3858f8be..e1ffac5b 100644 --- a/tests/functional/DocumentMaxAgeCest.php +++ b/tests/functional/DocumentMaxAgeCest.php @@ -6,7 +6,7 @@ class DocumentMaxAgeCest { public function _before( FunctionalTester $I ) { - $I->dontHaveOptionInDatabase( 'graphql_persisted_queries_section' ); + $I->dontHaveOptionInDatabase( 'graphql_cache_section' ); } public function _runQuery( FunctionalTester $I, $expected ) { @@ -25,22 +25,22 @@ public function _runQuery( FunctionalTester $I, $expected ) { public function queryShowsMaxAgeTest( FunctionalTester $I ) { $I->wantTo( 'See my custom max-age header in response for a graphql query' ); - $I->dontHaveOptionInDatabase( 'graphql_persisted_queries_section' ); + $I->dontHaveOptionInDatabase( 'graphql_cache_section' ); $this->_runQuery( $I, 600 ); - $I->haveOptionInDatabase( 'graphql_persisted_queries_section', [ 'global_max_age' => null ] ); + $I->haveOptionInDatabase( 'graphql_cache_section', [ 'global_max_age' => null ] ); $this->_runQuery( $I, 600 ); - $I->haveOptionInDatabase( 'graphql_persisted_queries_section', [ 'global_max_age' => 30 ] ); + $I->haveOptionInDatabase( 'graphql_cache_section', [ 'global_max_age' => 30 ] ); $this->_runQuery( $I, 30 ); - $I->haveOptionInDatabase( 'graphql_persisted_queries_section', [ 'global_max_age' => 10.5 ] ); + $I->haveOptionInDatabase( 'graphql_cache_section', [ 'global_max_age' => 10.5 ] ); $this->_runQuery( $I, 10 ); - $I->haveOptionInDatabase( 'graphql_persisted_queries_section', [ 'global_max_age' => -1 ] ); + $I->haveOptionInDatabase( 'graphql_cache_section', [ 'global_max_age' => -1 ] ); $this->_runQuery( $I, 600 ); - $I->haveOptionInDatabase( 'graphql_persisted_queries_section', [ 'global_max_age' => 0 ] ); + $I->haveOptionInDatabase( 'graphql_cache_section', [ 'global_max_age' => 0 ] ); $this->_runQuery( $I, 0 ); } diff --git a/tests/functional/LookupCest.php b/tests/functional/LookupCest.php index 80edeb79..cf00dd5e 100644 --- a/tests/functional/LookupCest.php +++ b/tests/functional/LookupCest.php @@ -4,8 +4,6 @@ class LookupCest { public function _before( FunctionalTester $I ) { // Make sure that is gone. $I->dontHavePostInDatabase( ['post_title' => 'Hello world!'] ); - - $I->dontHaveOptionInDatabase( 'graphql_persisted_queries_section' ); } // no id/hash. expect an error that it doesn't exist From ee4cc6aad3d408e9e7c6090e588784be60975921 Mon Sep 17 00:00:00 2001 From: Jason Bahl Date: Tue, 28 Jun 2022 15:33:48 -0600 Subject: [PATCH 3/9] - remove the publicly_queryable=>true statement from the graphql_document post_type --- src/Document.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Document.php b/src/Document.php index 93a8fdc5..949a087e 100644 --- a/src/Document.php +++ b/src/Document.php @@ -43,7 +43,6 @@ public function init() { 'singular_name' => __( 'GraphQLQuery', 'wp-graphql-smart-cache' ), ], 'public' => false, - 'publicly_queryable' => true, 'show_ui' => Settings::show_in_admin(), 'taxonomies' => [ self::ALIAS_TAXONOMY_NAME, From 4ddf034dec0c400299fe881bde7da4d985dcd493 Mon Sep 17 00:00:00 2001 From: Jason Bahl Date: Tue, 28 Jun 2022 16:53:57 -0600 Subject: [PATCH 4/9] - this adds an output message to the extensions payload when a response is returned from the object cache --- readme.txt | 37 +++++++++++----------- src/Admin/Settings.php | 4 +-- src/Cache/Results.php | 64 ++++++++++++++++++++++++++++++++++++-- wp-graphql-smart-cache.php | 2 +- 4 files changed, 83 insertions(+), 24 deletions(-) diff --git a/readme.txt b/readme.txt index 5896ce25..b041a9d7 100644 --- a/readme.txt +++ b/readme.txt @@ -1,18 +1,19 @@ -=== WP GraphQL Persisted Queries === -Contributors: markkelnar, jasonbahl -Tags: GraphQL -Requires at least: 4.5 -Tested up to: 5.6.1 -Requires PHP: 5.6 -Stable tag: 0.1.0 -License: GPLv2 or later -License URI: https://www.gnu.org/licenses/gpl-2.0.html - -== Description == - -WPGraphQL Persisted Queries for WPGraphQL, a plugin that provides an extendable GraphQL schema and API for any WordPress site. - -== Changelog == - -= 0.1 = -Initial +=== WP GraphQL Persisted Queries === +Contributors: markkelnar, jasonbahl +Tags: GraphQL +Requires at least: 4.5 +Tested up to: 5.6.1 +Requires PHP: 5.6 +Stable tag: 0.1.1 +License: GPLv2 or later +License URI: https://www.gnu.org/licenses/gpl-2.0.html + +== Description == + +WPGraphQL Persisted Queries for WPGraphQL, a plugin that provides an extendable GraphQL schema and API for any WordPress site. + +== Changelog == + += 0.1.1 = + +- Initial release to beta users diff --git a/src/Admin/Settings.php b/src/Admin/Settings.php index 6b4e1563..bfa707b2 100644 --- a/src/Admin/Settings.php +++ b/src/Admin/Settings.php @@ -110,7 +110,7 @@ function () { if ( $value < 0 || ! is_numeric( $value ) ) { return 0; } - return intval( $value ); + return (int) $value; }, ] ); @@ -138,7 +138,7 @@ function () { if ( $value < 0 || ! is_numeric( $value ) ) { return null; } - return intval( $value ); + return (int) $value; }, ] ); diff --git a/src/Cache/Results.php b/src/Cache/Results.php index 35215896..36f1be7a 100644 --- a/src/Cache/Results.php +++ b/src/Cache/Results.php @@ -12,10 +12,31 @@ class Results extends Query { const GLOBAL_DEFAULT_TTL = 600; + /** + * The cache key for the executed GraphQL Document + * + * @var string + */ + protected $cache_key = ''; + + /** + * The cached response of a GraphQL Query execution. False if it doesn't exist. + * + * @var mixed|bool|array|object + */ + protected $cached_result; + public function init() { + + $this->cached_result = false; + add_filter( 'pre_graphql_execute_request', [ $this, 'get_query_results_from_cache_cb' ], 10, 2 ); add_action( 'graphql_return_response', [ $this, 'save_query_results_to_cache_cb' ], 10, 7 ); add_action( 'wpgraphql_cache_purge_nodes', [ $this, 'purge_nodes_cb' ], 10, 2 ); + add_filter( 'graphql_request_results', [ + $this, + 'add_cache_key_to_response_extensions', + ], 10, 1 ); parent::init(); } @@ -31,7 +52,42 @@ public function init() { * @return string|false unique id for this request or false if query not provided */ public function the_results_key( $query_id, $query, $variables = null, $operation = null ) { - return $this->build_key( $query_id, $query, $variables, $operation ); + $this->cache_key = $this->build_key( $query_id, $query, $variables, $operation ); + return $this->cache_key; + } + + + /** + * Add a message to the extensions when a GraphQL request is returned from the GraphQL Object Cache + * + * @param mixed|array|object $response The response of the GraphQL Request + * + * @return array|mixed + */ + public function add_cache_key_to_response_extensions( $response ) { + + // if there's no cache key, or there is no cached_result return the response as-is + if ( empty( $this->cache_key ) || empty( $this->cached_result ) ) { + return $response; + } + + // construct the message to return + $message = [ + 'graphqlObjectCache' => [ + 'message' => __( 'This response is cached by WPGraphQL Smart Cache', 'wp-graphql-smart-cache' ), + 'cacheKey' => $this->cache_key, + ] + ]; + + if ( is_array( $response ) ) { + $response['extensions']['graphqlSmartCache'] = $message; + } if ( is_object( $response ) ) { + $response->extensions['graphqlSmartCache'] = $message; + } + + // return the modified response with the graphqlSmartCache message in the extensions output + return $response; + } /** @@ -56,8 +112,10 @@ public function get_query_results_from_cache_cb( $result, $request ) { return null; } - $cached_result = $this->get( $key ); - return ( false === $cached_result ) ? null : $cached_result; + $this->cached_result = $this->get( $key ); + + + return ( false === $this->cached_result ) ? null : $this->cached_result; } /** diff --git a/wp-graphql-smart-cache.php b/wp-graphql-smart-cache.php index 6dda8903..5662fbbc 100644 --- a/wp-graphql-smart-cache.php +++ b/wp-graphql-smart-cache.php @@ -6,7 +6,7 @@ * Author: WPGraphQL * Author URI: http://www.wpgraphql.com * Domain Path: /languages - * Version: 0.1.0-alpha + * Version: 0.1.1 * * Persisted Queries and Caching for WPGraphQL */ From a95e3628ae9704e5be68e2c41cbebc18afd11f18 Mon Sep 17 00:00:00 2001 From: Jason Bahl Date: Tue, 28 Jun 2022 16:57:10 -0600 Subject: [PATCH 5/9] - code sniffer fixes --- src/Cache/Results.php | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/Cache/Results.php b/src/Cache/Results.php index 36f1be7a..b05115bd 100644 --- a/src/Cache/Results.php +++ b/src/Cache/Results.php @@ -27,16 +27,20 @@ class Results extends Query { protected $cached_result; public function init() { - $this->cached_result = false; add_filter( 'pre_graphql_execute_request', [ $this, 'get_query_results_from_cache_cb' ], 10, 2 ); add_action( 'graphql_return_response', [ $this, 'save_query_results_to_cache_cb' ], 10, 7 ); add_action( 'wpgraphql_cache_purge_nodes', [ $this, 'purge_nodes_cb' ], 10, 2 ); - add_filter( 'graphql_request_results', [ - $this, - 'add_cache_key_to_response_extensions', - ], 10, 1 ); + add_filter( + 'graphql_request_results', + [ + $this, + 'add_cache_key_to_response_extensions', + ], + 10, + 1 + ); parent::init(); } @@ -74,9 +78,9 @@ public function add_cache_key_to_response_extensions( $response ) { // construct the message to return $message = [ 'graphqlObjectCache' => [ - 'message' => __( 'This response is cached by WPGraphQL Smart Cache', 'wp-graphql-smart-cache' ), + 'message' => __( 'This response is cached by WPGraphQL Smart Cache', 'wp-graphql-smart-cache' ), 'cacheKey' => $this->cache_key, - ] + ], ]; if ( is_array( $response ) ) { @@ -87,7 +91,6 @@ public function add_cache_key_to_response_extensions( $response ) { // return the modified response with the graphqlSmartCache message in the extensions output return $response; - } /** @@ -114,7 +117,6 @@ public function get_query_results_from_cache_cb( $result, $request ) { $this->cached_result = $this->get( $key ); - return ( false === $this->cached_result ) ? null : $this->cached_result; } From d4701a15cd1bbb773be3bbcad4c73bf99f285914 Mon Sep 17 00:00:00 2001 From: Jason Bahl Date: Tue, 28 Jun 2022 16:58:35 -0600 Subject: [PATCH 6/9] - update extension message --- src/Cache/Results.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cache/Results.php b/src/Cache/Results.php index b05115bd..6867ac0e 100644 --- a/src/Cache/Results.php +++ b/src/Cache/Results.php @@ -78,7 +78,7 @@ public function add_cache_key_to_response_extensions( $response ) { // construct the message to return $message = [ 'graphqlObjectCache' => [ - 'message' => __( 'This response is cached by WPGraphQL Smart Cache', 'wp-graphql-smart-cache' ), + 'message' => __( 'This response was not executed at run-time but has been returned from the GraphQL Object Cache', 'wp-graphql-smart-cache' ), 'cacheKey' => $this->cache_key, ], ]; From 5717020deee74fb22ff94147bf687eb53414ce2e Mon Sep 17 00:00:00 2001 From: Jason Bahl Date: Wed, 29 Jun 2022 19:59:46 -0400 Subject: [PATCH 7/9] - update README - update post type labels - update response to show for cached and uncached queries --- README.md | 131 +----------------------------------------- src/Cache/Results.php | 19 +++--- src/Document.php | 6 +- 3 files changed, 13 insertions(+), 143 deletions(-) diff --git a/README.md b/README.md index 42c50f0e..0e1fcc0b 100644 --- a/README.md +++ b/README.md @@ -1,130 +1,3 @@ -# Welcome - -Install the plugin in your WP environment. It is dependent on wp-grapqhl also being installed. - -Save a graphql query string for future use by an easy usable sha 256 hash or an alias name. - -## Saving Queries - -When submiting a query from your client, in the POST request provide a `queryId={value}` parameter with the submitted data. This `queryId` becomes the alias name of the saved query. It can then be used in future requests to invoke the query. - -Example POST data: - -``` -{ - "query": "{ - posts { - nodes { - title - } - } - }" - "queryId": "query-get-posts-title" -} -``` - -After that successful POST request, you can use the GET request to invoke the query by queryId. - - docker run -v $PWD:/app composer install --optimize-autoloader - -``` -https://domain.example/graphql?queryId=query-get-posts-title -``` - -## What about graphql variables? - -Queries that require variables to execute the graphql query, will need the variables specified with each POST or GET request. The variables are not saved with the query string in the system. - -Here is an example of invoking a saved query and providing variables. - -If this is the saved query in the system, - -POST - -``` -{ - "query": "query ($count:Int) { - posts(first:$count) { - nodes { - title - } - } - }" - "queryId": "query-get-posts-title" -} -``` - -The GET request would look like this to provide variables for the request, - -``` -https://domain.example/graphql?queryId=query-get-posts-title&variables={"count":2} -``` - -## What about queries with multiple operation names? - -Graphql query strings can contain multiple operations per string and an operation name is provided in the request to specify which query to invoke. The same is true for saved queries. - -Below is an example of a query string containing multiple operations that can be saved with queryId "multiple-query-get-posts". - -POST - -``` -{ - "query": " - query GetPosts { - posts { - nodes{ - id - title - } - } - } - query GetPostsSlug { - posts { - nodes{ - id - title - slug - } - } - } - ", - "queryId": "multiple-query-get-posts" -} -``` - -The GET request for the saved query specifying operation name looks like this, - -https://domain.example/graphql?queryId=multiple-query-get-posts&operationName=GetPostsSlug - -And if your query is multiple operations as well as variables, combine all of it together in your saved query and use the correct name/value parameters on the GET query requests. - -## Not Found Error - -If the queryId is not found in the system an error message will be returned in the response payload. A HTTP code of 200 is returned. - -``` -{ - "errors": [ - { - "message": "Query Not Found get-post-with-slug", - "extensions": { - "category": "request" - } - } - ], -} -``` - -## Enable caching results - -Log into wp-admin for the WP service. - -Select the GraphQL Settings tab. - -![Settings tab](./docs/images/wp-graphql-settings.png). -- -Check the box to enable results caching. - -![The checkbox to enable the results cache](./docs/images/wp-graphql-smart-cache-settings-cache.png). +# WP GraphQL Smart Cache - BETA USERS +If you've been contacted to beta test this plugin, you can access the docs here: https://docs.google.com/document/d/16n2LxJB5POBkkWF6OIC9et1BogLMiRf6qZwL7ofBT5k/edit?usp=sharing diff --git a/src/Cache/Results.php b/src/Cache/Results.php index 6867ac0e..63c63215 100644 --- a/src/Cache/Results.php +++ b/src/Cache/Results.php @@ -70,23 +70,20 @@ public function the_results_key( $query_id, $query, $variables = null, $operatio */ public function add_cache_key_to_response_extensions( $response ) { - // if there's no cache key, or there is no cached_result return the response as-is - if ( empty( $this->cache_key ) || empty( $this->cached_result ) ) { - return $response; - } + $message = []; - // construct the message to return - $message = [ - 'graphqlObjectCache' => [ + // if there's no cache key, or there is no cached_result return the response as-is + if ( ! empty( $this->cache_key ) && ! empty( $this->cached_result ) ) { + $message = [ 'message' => __( 'This response was not executed at run-time but has been returned from the GraphQL Object Cache', 'wp-graphql-smart-cache' ), 'cacheKey' => $this->cache_key, - ], - ]; + ]; + } if ( is_array( $response ) ) { - $response['extensions']['graphqlSmartCache'] = $message; + $response['extensions']['graphqlSmartCache']['graphqlObjectCache'] = $message; } if ( is_object( $response ) ) { - $response->extensions['graphqlSmartCache'] = $message; + $response->extensions['graphqlSmartCache']['graphqlObjectCache'] = $message; } // return the modified response with the graphqlSmartCache message in the extensions output diff --git a/src/Document.php b/src/Document.php index 949a087e..ded5c8f5 100644 --- a/src/Document.php +++ b/src/Document.php @@ -37,10 +37,10 @@ public function init() { register_post_type( self::TYPE_NAME, [ - 'description' => __( 'Saved GraphQL queries', 'wp-graphql-smart-cache' ), + 'description' => __( 'Saved GraphQL Documents', 'wp-graphql-smart-cache' ), 'labels' => [ - 'name' => __( 'GraphQLQueries', 'wp-graphql-smart-cache' ), - 'singular_name' => __( 'GraphQLQuery', 'wp-graphql-smart-cache' ), + 'name' => __( 'GraphQL Documents', 'wp-graphql-smart-cache' ), + 'singular_name' => __( 'GraphQL Document', 'wp-graphql-smart-cache' ), ], 'public' => false, 'show_ui' => Settings::show_in_admin(), From 3b116fb50795e9b83c119009a7629af4d92398f6 Mon Sep 17 00:00:00 2001 From: Jason Bahl Date: Wed, 29 Jun 2022 20:01:54 -0400 Subject: [PATCH 8/9] - code sniffer fix --- src/Cache/Results.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Cache/Results.php b/src/Cache/Results.php index 63c63215..067fbd45 100644 --- a/src/Cache/Results.php +++ b/src/Cache/Results.php @@ -69,7 +69,6 @@ public function the_results_key( $query_id, $query, $variables = null, $operatio * @return array|mixed */ public function add_cache_key_to_response_extensions( $response ) { - $message = []; // if there's no cache key, or there is no cached_result return the response as-is From d18e6f8929baae6d499e43235f3a490512e8305e Mon Sep 17 00:00:00 2001 From: Jason Bahl Date: Wed, 29 Jun 2022 20:03:16 -0400 Subject: [PATCH 9/9] no message --- src/Cache/Results.php | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/Cache/Results.php b/src/Cache/Results.php index 067fbd45..56dcb6ed 100644 --- a/src/Cache/Results.php +++ b/src/Cache/Results.php @@ -32,15 +32,7 @@ public function init() { add_filter( 'pre_graphql_execute_request', [ $this, 'get_query_results_from_cache_cb' ], 10, 2 ); add_action( 'graphql_return_response', [ $this, 'save_query_results_to_cache_cb' ], 10, 7 ); add_action( 'wpgraphql_cache_purge_nodes', [ $this, 'purge_nodes_cb' ], 10, 2 ); - add_filter( - 'graphql_request_results', - [ - $this, - 'add_cache_key_to_response_extensions', - ], - 10, - 1 - ); + add_filter( 'graphql_request_results', [ $this, 'add_cache_key_to_response_extensions' ], 10, 1 ); parent::init(); }