From 94668b481583cc15e15383747bf0901ed5248c2c Mon Sep 17 00:00:00 2001 From: Filip Ilic Date: Fri, 24 Oct 2025 14:13:17 +0200 Subject: [PATCH 1/4] add spinner to the interactive tasks --- assets/css/page-widgets/suggested-tasks.css | 17 +++++++ assets/js/recommendations/interactive-task.js | 47 ++++++++++++++++++- .../providers/class-blog-description.php | 8 ++-- .../class-disable-comment-pagination.php | 8 ++-- .../providers/class-disable-comments.php | 8 ++-- .../providers/class-hello-world.php | 8 ++-- .../providers/class-permalink-structure.php | 9 ++-- .../providers/class-sample-page.php | 8 ++-- .../class-search-engine-visibility.php | 8 ++-- .../providers/class-select-locale.php | 6 ++- .../providers/class-select-timezone.php | 6 ++- .../providers/class-set-date-format.php | 8 ++-- .../providers/class-site-icon.php | 8 ++-- .../class-update-term-description.php | 8 ++-- 14 files changed, 122 insertions(+), 35 deletions(-) diff --git a/assets/css/page-widgets/suggested-tasks.css b/assets/css/page-widgets/suggested-tasks.css index 14c90d395..9f43f4808 100644 --- a/assets/css/page-widgets/suggested-tasks.css +++ b/assets/css/page-widgets/suggested-tasks.css @@ -441,10 +441,22 @@ padding-top: 1rem; display: flex; justify-content: flex-end; + align-items: center; gap: 1rem; align-self: flex-end; width: 100%; + /* If there are no other elements in the form, align the button to the left. */ + &:only-child { + padding-top: 0; + justify-content: flex-start; + + /* Display the spinner after the button. */ + .prpl-spinner { + order: 99; + } + } + .prpl-button { cursor: pointer; margin: 0; @@ -456,6 +468,11 @@ } } + /* Display the spinner before the button. */ + .prpl-spinner { + order: -1; + } + } } diff --git a/assets/js/recommendations/interactive-task.js b/assets/js/recommendations/interactive-task.js index ca14cfb16..ffe697956 100644 --- a/assets/js/recommendations/interactive-task.js +++ b/assets/js/recommendations/interactive-task.js @@ -35,6 +35,8 @@ const prplInteractiveTaskFormListener = { formElement.addEventListener( 'submit', ( event ) => { event.preventDefault(); + prplInteractiveTaskFormListener.showLoading( formElement ); + // Get the form data. const formData = new FormData( formElement ); const settingsToPass = {}; @@ -56,6 +58,8 @@ const prplInteractiveTaskFormListener = { return response; } + prplInteractiveTaskFormListener.hideLoading( formElement ); + // This will trigger the celebration event (confetti) as well. prplSuggestedTask.maybeComplete( postId ).then( () => { // Close popover. @@ -76,6 +80,8 @@ const prplInteractiveTaskFormListener = { const formSubmitHandler = ( event ) => { event.preventDefault(); + prplInteractiveTaskFormListener.showLoading( formElement ); + callback() .then( ( response ) => { if ( true !== response.success ) { @@ -110,6 +116,9 @@ const prplInteractiveTaskFormListener = { ); } ) .finally( () => { + // Hide loading state. + prplInteractiveTaskFormListener.hideLoading( formElement ); + // Remove the form listener once the callback is executed. formElement.removeEventListener( 'submit', @@ -139,6 +148,8 @@ const prplInteractiveTaskFormListener = { formElement.addEventListener( 'submit', ( event ) => { event.preventDefault(); + prplInteractiveTaskFormListener.showLoading( formElement ); + const formData = new FormData( formElement ); const settingsToPass = {}; settingsToPass[ setting ] = settingCallbackValue( @@ -157,7 +168,6 @@ const prplInteractiveTaskFormListener = { }, } ) .then( ( response ) => { - console.log( response ); if ( true !== response.success ) { // Show error to the user. prplInteractiveTaskFormListener.showError( @@ -193,6 +203,10 @@ const prplInteractiveTaskFormListener = { error, popoverId ); + } ) + .finally( () => { + // Hide loading state. + prplInteractiveTaskFormListener.hideLoading( formElement ); } ); } ); }, @@ -241,4 +255,35 @@ const prplInteractiveTaskFormListener = { ); } }, + + /** + * Show loading state. + * + * @param {HTMLFormElement} formElement - The form element. + * @return {void} + */ + showLoading: ( formElement ) => { + // data-action="completeTask" + formElement.querySelector( 'button[type="submit"]' ).disabled = true; + + // Add spinner. + const spinner = document.createElement( 'span' ); + spinner.classList.add( 'prpl-spinner' ); + spinner.innerHTML = + ''; // WP spinner. + + // Append spinner after submit button. + formElement.querySelector( 'button[type="submit"]' ).after( spinner ); + }, + + /** + * Hide loading state. + * + * @param {HTMLFormElement} formElement - The form element. + * @return {void} + */ + hideLoading: ( formElement ) => { + formElement.querySelector( 'button[type="submit"]' ).disabled = false; + formElement.querySelector( 'span.prpl-spinner' )?.remove(); + }, }; diff --git a/classes/suggested-tasks/providers/class-blog-description.php b/classes/suggested-tasks/providers/class-blog-description.php index 91133ed0d..61ec8bb51 100644 --- a/classes/suggested-tasks/providers/class-blog-description.php +++ b/classes/suggested-tasks/providers/class-blog-description.php @@ -123,9 +123,11 @@ public function print_popover_form_contents() { placeholder="" > - +
+ +
- +
+ +
- +
+ +
- +
+ +
- + +
+ +
- +
+ +
- +
+ +
+
+ + +
+
+ + +
- +
+ +
- +
+ +
- +
+ +
Date: Fri, 24 Oct 2025 14:59:53 +0200 Subject: [PATCH 2/4] handle integrations, adjust error displaying of error message, add wpseo_titles --- assets/css/page-widgets/suggested-tasks.css | 4 ++ assets/js/recommendations/interactive-task.js | 48 +++++++++++-------- .../aioseo/class-archive-author.php | 8 ++-- .../aioseo/class-archive-date.php | 2 + .../class-crawl-settings-feed-authors.php | 8 ++-- .../class-crawl-settings-feed-comments.php | 8 ++-- .../yoast/class-add-yoast-providers.php | 1 + .../yoast/class-archive-author.php | 8 ++-- .../integrations/yoast/class-archive-date.php | 8 ++-- .../yoast/class-archive-format.php | 6 ++- .../class-crawl-settings-emoji-scripts.php | 8 ++-- .../class-crawl-settings-feed-authors.php | 8 ++-- ...ss-crawl-settings-feed-global-comments.php | 6 ++- .../integrations/yoast/class-media-pages.php | 8 ++-- .../yoast/class-organization-logo.php | 8 ++-- 15 files changed, 89 insertions(+), 50 deletions(-) diff --git a/assets/css/page-widgets/suggested-tasks.css b/assets/css/page-widgets/suggested-tasks.css index 9f43f4808..62a94dc27 100644 --- a/assets/css/page-widgets/suggested-tasks.css +++ b/assets/css/page-widgets/suggested-tasks.css @@ -206,6 +206,10 @@ &.prpl-note-error { color: var(--prpl-color-alert-error-text); background-color: var(--prpl-background-alert-error); + margin-bottom: 0; + + order: 98; /* One less than the spinner. */ + flex-grow: 1; .prpl-note-icon { color: var(--prpl-color-alert-error); diff --git a/assets/js/recommendations/interactive-task.js b/assets/js/recommendations/interactive-task.js index ffe697956..e7f511aa2 100644 --- a/assets/js/recommendations/interactive-task.js +++ b/assets/js/recommendations/interactive-task.js @@ -228,17 +228,12 @@ const prplInteractiveTaskFormListener = { console.error( 'Error in interactive task callback:', error ); - // Add error message. - const submitButton = formElement.querySelector( - 'button[type="submit"]' + // Check if there's already an error message

element right after the form + const existingErrorElement = formElement.parentNode.querySelector( + 'p.prpl-interactive-task-error-message' ); - if ( - submitButton && - ! formElement.querySelector( - '.prpl-interactive-task-error-message' - ) - ) { + if ( ! existingErrorElement ) { // Add paragraph with error message. const errorParagraph = document.createElement( 'p' ); errorParagraph.classList.add( @@ -248,11 +243,8 @@ const prplInteractiveTaskFormListener = { ); errorParagraph.textContent = prplL10n( 'somethingWentWrong' ); - // Append before submit button. - submitButton.parentNode.insertBefore( - errorParagraph, - submitButton - ); + // Append after the form element. + formElement.insertAdjacentElement( 'afterend', errorParagraph ); } }, @@ -263,8 +255,15 @@ const prplInteractiveTaskFormListener = { * @return {void} */ showLoading: ( formElement ) => { - // data-action="completeTask" - formElement.querySelector( 'button[type="submit"]' ).disabled = true; + let submitButton = formElement.querySelector( 'button[type="submit"]' ); + + if ( ! submitButton ) { + submitButton = formElement.querySelector( + 'button[data-action="completeTask"]' + ); + } + + submitButton.disabled = true; // Add spinner. const spinner = document.createElement( 'span' ); @@ -273,7 +272,7 @@ const prplInteractiveTaskFormListener = { ''; // WP spinner. // Append spinner after submit button. - formElement.querySelector( 'button[type="submit"]' ).after( spinner ); + submitButton.after( spinner ); }, /** @@ -283,7 +282,18 @@ const prplInteractiveTaskFormListener = { * @return {void} */ hideLoading: ( formElement ) => { - formElement.querySelector( 'button[type="submit"]' ).disabled = false; - formElement.querySelector( 'span.prpl-spinner' )?.remove(); + let submitButton = formElement.querySelector( 'button[type="submit"]' ); + + if ( ! submitButton ) { + submitButton = formElement.querySelector( + 'button[data-action="completeTask"]' + ); + } + + submitButton.disabled = false; + const spinner = formElement.querySelector( 'span.prpl-spinner' ); + if ( spinner ) { + spinner.remove(); + } }, }; diff --git a/classes/suggested-tasks/providers/integrations/aioseo/class-archive-author.php b/classes/suggested-tasks/providers/integrations/aioseo/class-archive-author.php index d055b64ab..c4197f105 100644 --- a/classes/suggested-tasks/providers/integrations/aioseo/class-archive-author.php +++ b/classes/suggested-tasks/providers/integrations/aioseo/class-archive-author.php @@ -136,9 +136,11 @@ public function print_popover_instructions() { */ public function print_popover_form_contents() { ?> - +

+ +
+
+
- +
+ +
- +
+ +
- +
+ +
- +
+ +
+
+ + +
- +
+ +
- +
+ +
+
+ + +
- +
+ +
- +
+ +
Date: Fri, 24 Oct 2025 15:17:43 +0200 Subject: [PATCH 3/4] fix order for special case --- classes/suggested-tasks/providers/class-disable-comments.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/suggested-tasks/providers/class-disable-comments.php b/classes/suggested-tasks/providers/class-disable-comments.php index dff1fc6dc..d9fdf364a 100644 --- a/classes/suggested-tasks/providers/class-disable-comments.php +++ b/classes/suggested-tasks/providers/class-disable-comments.php @@ -145,7 +145,7 @@ public function print_popover_instructions() { public function print_popover_form_contents() { ?>
-
From 15d99fbc26ca2abb144e8de2bf9075015700db2f Mon Sep 17 00:00:00 2001 From: Filip Ilic Date: Fri, 24 Oct 2025 16:53:57 +0200 Subject: [PATCH 4/4] move submit wrapper & button to common method where possible --- .../class-disable-comment-pagination.php | 8 +------ .../providers/class-hello-world.php | 8 +------ .../providers/class-permalink-structure.php | 7 +------ .../providers/class-sample-page.php | 8 +------ .../class-search-engine-visibility.php | 8 +------ .../providers/class-select-locale.php | 9 ++------ .../providers/class-select-timezone.php | 6 +----- .../providers/class-set-date-format.php | 6 +----- .../providers/class-tasks-interactive.php | 21 +++++++++++++++++++ .../aioseo/class-archive-author.php | 8 +------ .../aioseo/class-archive-date.php | 8 +------ .../class-crawl-settings-feed-authors.php | 8 +------ .../class-crawl-settings-feed-comments.php | 8 +------ .../yoast/class-archive-author.php | 8 +------ .../integrations/yoast/class-archive-date.php | 8 +------ .../yoast/class-archive-format.php | 8 +------ .../class-crawl-settings-emoji-scripts.php | 8 +------ .../class-crawl-settings-feed-authors.php | 8 +------ ...ss-crawl-settings-feed-global-comments.php | 8 +------ .../integrations/yoast/class-media-pages.php | 8 +------ 20 files changed, 41 insertions(+), 128 deletions(-) diff --git a/classes/suggested-tasks/providers/class-disable-comment-pagination.php b/classes/suggested-tasks/providers/class-disable-comment-pagination.php index b6c02550a..3d46db9e2 100644 --- a/classes/suggested-tasks/providers/class-disable-comment-pagination.php +++ b/classes/suggested-tasks/providers/class-disable-comment-pagination.php @@ -120,13 +120,7 @@ public function print_popover_instructions() { * @return void */ public function print_popover_form_contents() { - ?> -
- -
- print_submit_button( \__( 'Disable comment pagination', 'progress-planner' ) ); } /** diff --git a/classes/suggested-tasks/providers/class-hello-world.php b/classes/suggested-tasks/providers/class-hello-world.php index 66ba95b5e..fe431f419 100644 --- a/classes/suggested-tasks/providers/class-hello-world.php +++ b/classes/suggested-tasks/providers/class-hello-world.php @@ -139,13 +139,7 @@ public function should_add_task() { * @return void */ public function print_popover_form_contents() { - ?> -
- -
- print_submit_button( \__( 'Delete the "Hello World!" post', 'progress-planner' ) ); } /** diff --git a/classes/suggested-tasks/providers/class-permalink-structure.php b/classes/suggested-tasks/providers/class-permalink-structure.php index 33c8ae315..40b546d22 100644 --- a/classes/suggested-tasks/providers/class-permalink-structure.php +++ b/classes/suggested-tasks/providers/class-permalink-structure.php @@ -236,13 +236,8 @@ public function print_popover_form_contents() { - -
- -
print_submit_button( \__( 'Set permalink structure', 'progress-planner' ) ); } /** diff --git a/classes/suggested-tasks/providers/class-sample-page.php b/classes/suggested-tasks/providers/class-sample-page.php index 46609cfd7..e7ae313cf 100644 --- a/classes/suggested-tasks/providers/class-sample-page.php +++ b/classes/suggested-tasks/providers/class-sample-page.php @@ -138,13 +138,7 @@ public function should_add_task() { * @return void */ public function print_popover_form_contents() { - ?> -
- -
- print_submit_button( \__( 'Delete the "Sample Page" page', 'progress-planner' ) ); } /** diff --git a/classes/suggested-tasks/providers/class-search-engine-visibility.php b/classes/suggested-tasks/providers/class-search-engine-visibility.php index 8e779acb7..54ec0dd7f 100644 --- a/classes/suggested-tasks/providers/class-search-engine-visibility.php +++ b/classes/suggested-tasks/providers/class-search-engine-visibility.php @@ -112,13 +112,7 @@ public function print_popover_instructions() { * @return void */ public function print_popover_form_contents() { - ?> -
- -
- print_submit_button( \__( 'Allow search engines to index your site', 'progress-planner' ) ); } /** diff --git a/classes/suggested-tasks/providers/class-select-locale.php b/classes/suggested-tasks/providers/class-select-locale.php index a5bd352ef..5433671cb 100644 --- a/classes/suggested-tasks/providers/class-select-locale.php +++ b/classes/suggested-tasks/providers/class-select-locale.php @@ -225,13 +225,8 @@ public function print_popover_form_contents() { 'show_available_translations' => \current_user_can( 'install_languages' ) && \wp_can_install_language_pack(), ] ); - ?> -
- -
- print_submit_button( \__( 'Select locale', 'progress-planner' ) ); } /** diff --git a/classes/suggested-tasks/providers/class-select-timezone.php b/classes/suggested-tasks/providers/class-select-timezone.php index 20be1ce4a..702010cc0 100644 --- a/classes/suggested-tasks/providers/class-select-timezone.php +++ b/classes/suggested-tasks/providers/class-select-timezone.php @@ -143,12 +143,8 @@ public function print_popover_form_contents() { -
- -
print_submit_button( \__( 'Set site timezone', 'progress-planner' ) ); } /** diff --git a/classes/suggested-tasks/providers/class-set-date-format.php b/classes/suggested-tasks/providers/class-set-date-format.php index 7ce280063..fdd1f7128 100644 --- a/classes/suggested-tasks/providers/class-set-date-format.php +++ b/classes/suggested-tasks/providers/class-set-date-format.php @@ -242,12 +242,8 @@ public function print_popover_form_contents() {

-
- -
print_submit_button( \__( 'Set date format', 'progress-planner' ) ); } /** diff --git a/classes/suggested-tasks/providers/class-tasks-interactive.php b/classes/suggested-tasks/providers/class-tasks-interactive.php index 98941d027..97f721201 100644 --- a/classes/suggested-tasks/providers/class-tasks-interactive.php +++ b/classes/suggested-tasks/providers/class-tasks-interactive.php @@ -206,6 +206,27 @@ public function print_popover_instructions() { echo '

' . \wp_kses_post( $description ) . '

'; } + /** + * Print the submit button. + * + * @param string $button_text The text for the button. + * If empty, the default text "Submit" will be used. + * + * @return void + */ + protected function print_submit_button( $button_text = '' ) { + if ( empty( $button_text ) ) { + $button_text = \__( 'Submit', 'progress-planner' ); + } + ?> +
+ +
+ -
- -
- print_submit_button( \__( 'Noindex the author archive', 'progress-planner' ) ); } /** diff --git a/classes/suggested-tasks/providers/integrations/aioseo/class-archive-date.php b/classes/suggested-tasks/providers/integrations/aioseo/class-archive-date.php index 7ac42040b..86ed48d7b 100644 --- a/classes/suggested-tasks/providers/integrations/aioseo/class-archive-date.php +++ b/classes/suggested-tasks/providers/integrations/aioseo/class-archive-date.php @@ -121,13 +121,7 @@ public function print_popover_instructions() { * @return void */ public function print_popover_form_contents() { - ?> -
- -
- print_submit_button( \__( 'Noindex the date archive', 'progress-planner' ) ); } /** diff --git a/classes/suggested-tasks/providers/integrations/aioseo/class-crawl-settings-feed-authors.php b/classes/suggested-tasks/providers/integrations/aioseo/class-crawl-settings-feed-authors.php index c0413335c..ddcfcc05a 100644 --- a/classes/suggested-tasks/providers/integrations/aioseo/class-crawl-settings-feed-authors.php +++ b/classes/suggested-tasks/providers/integrations/aioseo/class-crawl-settings-feed-authors.php @@ -132,13 +132,7 @@ public function print_popover_instructions() { * @return void */ public function print_popover_form_contents() { - ?> -
- -
- print_submit_button( \__( 'Disable author RSS feeds', 'progress-planner' ) ); } /** diff --git a/classes/suggested-tasks/providers/integrations/aioseo/class-crawl-settings-feed-comments.php b/classes/suggested-tasks/providers/integrations/aioseo/class-crawl-settings-feed-comments.php index de84eaf1d..a0a42e7e5 100644 --- a/classes/suggested-tasks/providers/integrations/aioseo/class-crawl-settings-feed-comments.php +++ b/classes/suggested-tasks/providers/integrations/aioseo/class-crawl-settings-feed-comments.php @@ -100,13 +100,7 @@ public function print_popover_instructions() { * @return void */ public function print_popover_form_contents() { - ?> -
- -
- print_submit_button( \__( 'Disable comment RSS feeds', 'progress-planner' ) ); } /** diff --git a/classes/suggested-tasks/providers/integrations/yoast/class-archive-author.php b/classes/suggested-tasks/providers/integrations/yoast/class-archive-author.php index d86e48fd0..367d98ac3 100644 --- a/classes/suggested-tasks/providers/integrations/yoast/class-archive-author.php +++ b/classes/suggested-tasks/providers/integrations/yoast/class-archive-author.php @@ -125,13 +125,7 @@ public function print_popover_instructions() { * @return void */ public function print_popover_form_contents() { - ?> -
- -
- print_submit_button( \__( 'Disable', 'progress-planner' ) ); } /** diff --git a/classes/suggested-tasks/providers/integrations/yoast/class-archive-date.php b/classes/suggested-tasks/providers/integrations/yoast/class-archive-date.php index c2c63837f..48173c5f7 100644 --- a/classes/suggested-tasks/providers/integrations/yoast/class-archive-date.php +++ b/classes/suggested-tasks/providers/integrations/yoast/class-archive-date.php @@ -112,13 +112,7 @@ public function print_popover_instructions() { * @return void */ public function print_popover_form_contents() { - ?> -
- -
- print_submit_button( \__( 'Disable', 'progress-planner' ) ); } /** diff --git a/classes/suggested-tasks/providers/integrations/yoast/class-archive-format.php b/classes/suggested-tasks/providers/integrations/yoast/class-archive-format.php index c8f509e57..0041f168c 100644 --- a/classes/suggested-tasks/providers/integrations/yoast/class-archive-format.php +++ b/classes/suggested-tasks/providers/integrations/yoast/class-archive-format.php @@ -125,13 +125,7 @@ public function print_popover_instructions() { * @return void */ public function print_popover_form_contents() { - ?> -
- -
- print_submit_button( \__( 'Disable', 'progress-planner' ) ); } /** diff --git a/classes/suggested-tasks/providers/integrations/yoast/class-crawl-settings-emoji-scripts.php b/classes/suggested-tasks/providers/integrations/yoast/class-crawl-settings-emoji-scripts.php index 80fd93f6a..9867a75bc 100644 --- a/classes/suggested-tasks/providers/integrations/yoast/class-crawl-settings-emoji-scripts.php +++ b/classes/suggested-tasks/providers/integrations/yoast/class-crawl-settings-emoji-scripts.php @@ -104,13 +104,7 @@ public function print_popover_instructions() { * @return void */ public function print_popover_form_contents() { - ?> -
- -
- print_submit_button( \__( 'Remove', 'progress-planner' ) ); } /** diff --git a/classes/suggested-tasks/providers/integrations/yoast/class-crawl-settings-feed-authors.php b/classes/suggested-tasks/providers/integrations/yoast/class-crawl-settings-feed-authors.php index 3bd3805ed..ff550f62e 100644 --- a/classes/suggested-tasks/providers/integrations/yoast/class-crawl-settings-feed-authors.php +++ b/classes/suggested-tasks/providers/integrations/yoast/class-crawl-settings-feed-authors.php @@ -136,13 +136,7 @@ public function print_popover_instructions() { * @return void */ public function print_popover_form_contents() { - ?> -
- -
- print_submit_button( \__( 'Remove', 'progress-planner' ) ); } /** diff --git a/classes/suggested-tasks/providers/integrations/yoast/class-crawl-settings-feed-global-comments.php b/classes/suggested-tasks/providers/integrations/yoast/class-crawl-settings-feed-global-comments.php index 012fa8e60..95af3c30e 100644 --- a/classes/suggested-tasks/providers/integrations/yoast/class-crawl-settings-feed-global-comments.php +++ b/classes/suggested-tasks/providers/integrations/yoast/class-crawl-settings-feed-global-comments.php @@ -104,13 +104,7 @@ public function print_popover_instructions() { * @return void */ public function print_popover_form_contents() { - ?> -
- -
- print_submit_button( \__( 'Remove', 'progress-planner' ) ); } /** diff --git a/classes/suggested-tasks/providers/integrations/yoast/class-media-pages.php b/classes/suggested-tasks/providers/integrations/yoast/class-media-pages.php index f72e5ad8c..64371fa8e 100644 --- a/classes/suggested-tasks/providers/integrations/yoast/class-media-pages.php +++ b/classes/suggested-tasks/providers/integrations/yoast/class-media-pages.php @@ -98,13 +98,7 @@ public function print_popover_instructions() { * @return void */ public function print_popover_form_contents() { - ?> -
- -
- print_submit_button( \__( 'Disable', 'progress-planner' ) ); } /**