From e9f4fc0910d7e0337e77eb16090d7ec6c1f9af50 Mon Sep 17 00:00:00 2001
From: Mark Kelnar <749603+markkelnar@users.noreply.github.com>
Date: Tue, 22 Aug 2023 16:07:49 -0500
Subject: [PATCH 1/4] When published query is edited, offer save as new
---
src/Admin/Editor.php | 70 ++++++++++++++++++++++++++++++++++++++++--
src/Document/Group.php | 12 ++++++++
2 files changed, 80 insertions(+), 2 deletions(-)
diff --git a/src/Admin/Editor.php b/src/Admin/Editor.php
index 3df834ff..67525a6e 100644
--- a/src/Admin/Editor.php
+++ b/src/Admin/Editor.php
@@ -10,6 +10,7 @@
use WPGraphQL\SmartCache\AdminErrors;
use WPGraphQL\SmartCache\Document;
use WPGraphQL\SmartCache\Document\Grant;
+use WPGraphQL\SmartCache\Document\Group;
use WPGraphQL\SmartCache\Document\MaxAge;
use GraphQL\Error\SyntaxError;
use GraphQL\Server\RequestError;
@@ -34,6 +35,7 @@ public function admin_init() {
add_filter( sprintf( 'manage_edit-%s_sortable_columns', Document::TYPE_NAME ), [ $this, 'make_excerpt_column_sortable_in_admin_cb' ], 10, 1 );
add_filter( 'wp_editor_settings', [ $this, 'wp_editor_settings' ], 10, 2 );
+ add_action( 'post_submitbox_misc_actions', [ $this, 'draw_save_as_new_checkbox_cb' ] );
}
/**
@@ -71,7 +73,8 @@ public function validate_and_pre_save_cb( $data, $post ) {
return $data;
}
- $document = new Document();
+ $document = new Document();
+ $existing_post = get_post( $post['ID'], ARRAY_A );
try {
// Check for empty post_content when publishing the query and throw
@@ -81,6 +84,35 @@ public function validate_and_pre_save_cb( $data, $post ) {
$data['post_content'] = $document->valid_or_throw( $post['post_content'], $post['ID'] );
+ // If post is already published, and graphql query string is different on save, save as a new post/clone/copy.
+ if ( 'publish' === $existing_post['post_status'] && $data['post_content'] !== $existing_post['post_content'] ) {
+
+ // phpcs:ignore
+ if ( isset( $_POST['graphql_query_save_new'] ) && 'save_as_new' === $_POST['graphql_query_save_new'] ) {
+ // phpcs:ignore
+ unset( $_POST['graphql_query_save_new'] );
+
+ // Reset some data in the post before save as new. $data doesn't have a post_id.
+ $data['post_status'] = 'draft';
+ $data['post_date_gmt'] = '0000-00-00 00:00:00';
+ $data['post_date'] = '';
+ if ( $data['post_title'] === $existing_post['post_title'] ) {
+ $data['post_title'] = $existing_post['post_title'] . ' (copy)';
+ }
+
+ $new_post_id = wp_insert_post( $data );
+
+ $group = new Group();
+ $group->save( $new_post_id, $group->get( $existing_post['ID'] ) );
+
+ // Redirect to the new post edit page after save
+ wp_safe_redirect( admin_url( sprintf( '/post.php?post=%d&action=edit', $new_post_id ) ) );
+ exit;
+
+ } else {
+ throw new RequestError( __( 'Changing query for published query is not allowed. Select the save as new and publish again.', 'wp-graphql-smart-cache' ) );
+ }
+ }
} catch ( RequestError $e ) {
AdminErrors::add_message( $e->getMessage() );
@@ -88,7 +120,6 @@ public function validate_and_pre_save_cb( $data, $post ) {
if ( 'publish' === $post['post_status'] ) {
// If has an existing published post and trying to publish with errors, bail before save_post
- $existing_post = get_post( $post['ID'], ARRAY_A );
if ( $existing_post && 'publish' === $existing_post['post_status'] ) {
wp_safe_redirect( admin_url( sprintf( '/post.php?post=%d&action=edit', $post['ID'] ) ) );
@@ -363,4 +394,39 @@ public function wp_editor_settings( $settings, $editor_id ) {
return $settings;
}
+
+ public function draw_save_as_new_checkbox_cb( $post ) {
+ $post_id = get_the_ID();
+
+ if ( Document::TYPE_NAME !== $post->post_type ) {
+ return;
+ }
+
+ if ( 'publish' !== $post->post_status ) {
+ return;
+ }
+
+ $html = '
';
+ $html .= '';
+ $html .= '
';
+ $html .= '
';
+
+ $allowed_html = [
+ 'div' => [
+ 'class' => true,
+ ],
+ 'input' => [
+ 'type' => true,
+ 'id' => true,
+ 'name' => true,
+ 'value' => true,
+ 'checked' => true,
+ ],
+ 'br' => true,
+ ];
+ echo wp_kses(
+ $html,
+ $allowed_html
+ );
+ }
}
diff --git a/src/Document/Group.php b/src/Document/Group.php
index 6bc3012b..eab04802 100644
--- a/src/Document/Group.php
+++ b/src/Document/Group.php
@@ -51,4 +51,16 @@ public static function get( $post_id ) {
$item = get_the_terms( $post_id, self::TAXONOMY_NAME );
return ! is_wp_error( $item ) && isset( $item[0] ) && property_exists( $item[0], 'name' ) ? $item[0]->name : '';
}
+
+ /**
+ * Save the data
+ *
+ * @param int $post_id
+ * @param string $value
+ * @return array|false|\WP_Error Array of term taxonomy IDs of affected terms. WP_Error or false on failure.
+ */
+ public function save( $post_id, $value ) {
+ return wp_set_post_terms( $post_id, $value, self::TAXONOMY_NAME );
+ }
+
}
From e140874f49f1c87f354efd1b1a90f569ef96d6b5 Mon Sep 17 00:00:00 2001
From: Mark Kelnar <749603+markkelnar@users.noreply.github.com>
Date: Tue, 22 Aug 2023 16:29:11 -0500
Subject: [PATCH 2/4] some phpstan fixes
---
src/Admin/Editor.php | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/Admin/Editor.php b/src/Admin/Editor.php
index 67525a6e..b86c2693 100644
--- a/src/Admin/Editor.php
+++ b/src/Admin/Editor.php
@@ -395,6 +395,10 @@ public function wp_editor_settings( $settings, $editor_id ) {
return $settings;
}
+ /**
+ * @param \WP_Post $post
+ * @return void
+ */
public function draw_save_as_new_checkbox_cb( $post ) {
$post_id = get_the_ID();
@@ -411,6 +415,7 @@ public function draw_save_as_new_checkbox_cb( $post ) {
$html .= '
';
$html .= '';
+ /** @var array[] */
$allowed_html = [
'div' => [
'class' => true,
From 1dc6e33b40dff64dbbfe9dd9aa1fd51df8779fc8 Mon Sep 17 00:00:00 2001
From: Mark Kelnar <749603+markkelnar@users.noreply.github.com>
Date: Tue, 22 Aug 2023 16:53:24 -0500
Subject: [PATCH 3/4] When saving/updating a published post
---
composer.lock | 28 ++++++++++++++--------------
src/Admin/Editor.php | 5 +++--
2 files changed, 17 insertions(+), 16 deletions(-)
diff --git a/composer.lock b/composer.lock
index 8f2e27e7..4a1db18c 100644
--- a/composer.lock
+++ b/composer.lock
@@ -1645,7 +1645,7 @@
},
{
"name": "illuminate/collections",
- "version": "v10.19.0",
+ "version": "v10.20.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/collections.git",
@@ -1700,7 +1700,7 @@
},
{
"name": "illuminate/conditionable",
- "version": "v10.19.0",
+ "version": "v10.20.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/conditionable.git",
@@ -1746,7 +1746,7 @@
},
{
"name": "illuminate/contracts",
- "version": "v10.19.0",
+ "version": "v10.20.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/contracts.git",
@@ -1794,7 +1794,7 @@
},
{
"name": "illuminate/macroable",
- "version": "v10.19.0",
+ "version": "v10.20.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/macroable.git",
@@ -1840,16 +1840,16 @@
},
{
"name": "illuminate/support",
- "version": "v10.19.0",
+ "version": "v10.20.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/support.git",
- "reference": "0a8526d55756955fcec6be7c2c6cd14d915c8c0f"
+ "reference": "38d3e064b7b9420d2173f23a31a435bde221b56d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/illuminate/support/zipball/0a8526d55756955fcec6be7c2c6cd14d915c8c0f",
- "reference": "0a8526d55756955fcec6be7c2c6cd14d915c8c0f",
+ "url": "https://api.github.com/repos/illuminate/support/zipball/38d3e064b7b9420d2173f23a31a435bde221b56d",
+ "reference": "38d3e064b7b9420d2173f23a31a435bde221b56d",
"shasum": ""
},
"require": {
@@ -1907,7 +1907,7 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
- "time": "2023-08-14T21:56:59+00:00"
+ "time": "2023-08-21T13:45:59+00:00"
},
{
"name": "ivome/graphql-relay-php",
@@ -2951,16 +2951,16 @@
},
{
"name": "phpstan/phpstan",
- "version": "1.10.29",
+ "version": "1.10.30",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
- "reference": "ee5d8f2d3977fb09e55603eee6fb53bdd76ee9c1"
+ "reference": "2910afdd3fe33e5afd71c09f3fb0d0845b48c410"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan/zipball/ee5d8f2d3977fb09e55603eee6fb53bdd76ee9c1",
- "reference": "ee5d8f2d3977fb09e55603eee6fb53bdd76ee9c1",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/2910afdd3fe33e5afd71c09f3fb0d0845b48c410",
+ "reference": "2910afdd3fe33e5afd71c09f3fb0d0845b48c410",
"shasum": ""
},
"require": {
@@ -3009,7 +3009,7 @@
"type": "tidelift"
}
],
- "time": "2023-08-14T13:24:11+00:00"
+ "time": "2023-08-22T13:48:25+00:00"
},
{
"name": "phpunit/php-code-coverage",
diff --git a/src/Admin/Editor.php b/src/Admin/Editor.php
index b86c2693..2f1e2295 100644
--- a/src/Admin/Editor.php
+++ b/src/Admin/Editor.php
@@ -84,9 +84,10 @@ public function validate_and_pre_save_cb( $data, $post ) {
$data['post_content'] = $document->valid_or_throw( $post['post_content'], $post['ID'] );
- // If post is already published, and graphql query string is different on save, save as a new post/clone/copy.
- if ( 'publish' === $existing_post['post_status'] && $data['post_content'] !== $existing_post['post_content'] ) {
+ // If post is already published and saving as published, and graphql query string is different on save
+ if ( 'publish' === $existing_post['post_status'] && 'publish' === $post['post_status'] && $data['post_content'] !== $existing_post['post_content'] ) {
+ // If selected to save as new
// phpcs:ignore
if ( isset( $_POST['graphql_query_save_new'] ) && 'save_as_new' === $_POST['graphql_query_save_new'] ) {
// phpcs:ignore
From c5056942a104ee443be947072c0acc7783d6e1b6 Mon Sep 17 00:00:00 2001
From: Mark Kelnar <749603+markkelnar@users.noreply.github.com>
Date: Thu, 24 Aug 2023 11:34:57 -0500
Subject: [PATCH 4/4] Add tests for admin editor save-as checkbox and errors
---
src/Admin/Editor.php | 8 +-
tests/functional/AdminEditorDocumentCest.php | 88 ++++++++++++++++++++
2 files changed, 92 insertions(+), 4 deletions(-)
diff --git a/src/Admin/Editor.php b/src/Admin/Editor.php
index 2f1e2295..e305fb5f 100644
--- a/src/Admin/Editor.php
+++ b/src/Admin/Editor.php
@@ -85,8 +85,7 @@ public function validate_and_pre_save_cb( $data, $post ) {
$data['post_content'] = $document->valid_or_throw( $post['post_content'], $post['ID'] );
// If post is already published and saving as published, and graphql query string is different on save
- if ( 'publish' === $existing_post['post_status'] && 'publish' === $post['post_status'] && $data['post_content'] !== $existing_post['post_content'] ) {
-
+ if ( 'publish' === $existing_post['post_status'] && 'publish' === $post['post_status'] ) {
// If selected to save as new
// phpcs:ignore
if ( isset( $_POST['graphql_query_save_new'] ) && 'save_as_new' === $_POST['graphql_query_save_new'] ) {
@@ -109,8 +108,9 @@ public function validate_and_pre_save_cb( $data, $post ) {
// Redirect to the new post edit page after save
wp_safe_redirect( admin_url( sprintf( '/post.php?post=%d&action=edit', $new_post_id ) ) );
exit;
+ }
- } else {
+ if ( $data['post_content'] !== $existing_post['post_content'] ) {
throw new RequestError( __( 'Changing query for published query is not allowed. Select the save as new and publish again.', 'wp-graphql-smart-cache' ) );
}
}
@@ -413,7 +413,7 @@ public function draw_save_as_new_checkbox_cb( $post ) {
$html = '';
$html .= '';
- $html .= '
';
+ $html .= '
';
$html .= '
';
/** @var array[] */
diff --git a/tests/functional/AdminEditorDocumentCest.php b/tests/functional/AdminEditorDocumentCest.php
index eec41963..616b8ec6 100644
--- a/tests/functional/AdminEditorDocumentCest.php
+++ b/tests/functional/AdminEditorDocumentCest.php
@@ -487,4 +487,92 @@ public function createNewQueryWithInvalidContentThenTrashItTest( FunctionalTeste
$I->dontSeeElement('//*[@id="plugin-message"]');
$I->dontSee('Invalid graphql query string "{ __typename broken"', '//*[@id="plugin-message"]');
}
+
+ public function havePublishedQueryWhenChangeQueryStringThePublishShowsErrorTest( FunctionalTester $I ) {
+ $post_title = 'test-post';
+ $original_query = '{ __typename }';
+ $normalized_query_string = "{\n __typename\n}\n";
+ $new_query = '{ __typename __typename }';
+ $the_new_normal = "{\n __typename\n __typename\n}\n";
+
+ // Create a new query in the admin editor
+ $I->loginAsAdmin();
+ $I->amOnPage( '/wp-admin/post-new.php?post_type=graphql_document');
+
+ // Add title should trigger auto-draft, but not save document
+ $I->fillField( "//input[@name='post_title']", $post_title);
+ $I->fillField( 'content', $original_query);
+ $I->fillField( 'graphql_query_maxage', '200');
+
+ // Publish post
+ $I->click('#publish');
+
+ $post_id_1 = $I->grabValueFrom(['name' => 'post_ID']);
+
+ $I->seePostInDatabase( [
+ 'post_title' => $post_title,
+ 'post_status' => 'publish',
+ 'post_content' => $normalized_query_string,
+ ]);
+
+ // new query
+ $I->fillField( 'content', $new_query );
+
+ // Shows save-as-new check box
+ $I->seeElement('//*[@id="graphql_query_save_new"]');
+ $I->see('Save As Draft');
+ $I->dontSeeCheckboxIsChecked("//input[@type='checkbox' and @name='graphql_query_save_new']");
+
+ // // Publish post button
+ $I->click('#publish');
+
+ $post_id_2 = $I->grabValueFrom(['name' => 'post_ID']);
+ $I->assertEquals( $post_id_1, $post_id_2 );
+ $I->seeInCurrentUrl( "/wp-admin/post.php?post=$post_id_1&action=edit" );
+
+ // Should not see success of the publish.
+ $I->dontSeeElement('//*[@id="message"]');
+ $I->dontSee('Post published.');
+ $I->dontSee('Post updated.');
+ $I->dontSee('Post saved.');
+ $I->dontSee('Publish immediately'); // has date because already published
+
+ // Shows error message
+ $I->seeElement('//*[@id="plugin-message"]');
+ $I->see('Changing query for published query is not allowed. Select the save as new and publish again.', '//*[@id="plugin-message"]');
+
+ // Shows save-as-new check box
+ $I->seeElement('//*[@id="graphql_query_save_new"]');
+ $I->see('Save As Draft');
+ $I->dontSeeCheckboxIsChecked("//input[@type='checkbox' and @name='graphql_query_save_new']");
+
+ // new query
+ $I->fillField( 'content', $new_query );
+
+ // Select the save as new
+ $I->checkOption("//input[@type='checkbox' and @name='graphql_query_save_new']");
+
+ // // Publish post button
+ $I->click('#publish');
+
+ $post_id_3 = $I->grabValueFrom(['name' => 'post_ID']);
+ $I->assertNotEquals( $post_id_1, $post_id_3 );
+ $I->seeInCurrentUrl( "/wp-admin/post.php?post=$post_id_3&action=edit" );
+
+ // should not see our admin error
+ $I->dontSeeElement('//*[@id="plugin-message"]');
+
+ // Saves the different query as draft with new title
+ $I->seePostInDatabase( [
+ 'post_title' => "$post_title (copy)",
+ 'post_status' => 'draft',
+ 'post_content' => $the_new_normal,
+ ]);
+
+ $post_id = $I->grabValueFrom(['name' => 'post_ID']);
+
+ // Should also save the other data for the new post
+ $I->seeInField(['name' => 'graphql_query_maxage'], '200');
+ }
+
}