diff --git a/admin/class-convertkit-admin-legacy-resource-notice.php b/admin/class-convertkit-admin-legacy-resource-notice.php new file mode 100644 index 000000000..259555f0a --- /dev/null +++ b/admin/class-convertkit-admin-legacy-resource-notice.php @@ -0,0 +1,265 @@ +get_current_post_id(); + if ( ! $post_id ) { + return; + } + + // Get warnings. + $warnings = $this->get_legacy_warnings_for_post_settings( $post_id ); + + // Bail if no warnings are found. + if ( empty( $warnings ) ) { + return; + } + + // Output warnings. + ?> +
+

+ : + +

+ +
+ get_current_post_id(); + if ( ! $post_id ) { + return; + } + + // Get warnings. + $warnings = $this->get_legacy_warnings_for_post_settings( $post_id ); + + // Bail if no warnings are found. + if ( empty( $warnings ) ) { + return; + } + + // Enqueue script. + wp_enqueue_script( + 'convertkit-admin-legacy-resource-notice', + CONVERTKIT_PLUGIN_URL . 'resources/backend/js/legacy-resource-notice.js', + array( 'wp-data', 'wp-notices' ), + CONVERTKIT_PLUGIN_VERSION, + true + ); + + // Localize script. + wp_localize_script( + 'convertkit-admin-legacy-resource-notice', + 'convertkit_legacy_resource_notice', + array( + 'id' => self::GUTENBERG_NOTICE_ID, + 'intro' => __( 'Kit: This page uses one or more legacy Kit resources that are no longer offered for new selections. The following continue to work, but we recommend migrating:', 'convertkit' ), + 'warnings' => $warnings, + ) + ); + + } + + /** + * Returns an array of warning strings for the given Post, if the Post settings + * reference a Legacy Form or Legacy Landing Page. + * + * @since 3.3.7 + * + * @param int $post_id Post ID. + * @return array + */ + private function get_legacy_warnings_for_post_settings( $post_id ) { + + // Get Post settings. + $convertkit_post = new ConvertKit_Post( $post_id ); + $settings = $convertkit_post->get(); + + // Get resources. + $forms = new ConvertKit_Resource_Forms(); + $landing_pages = new ConvertKit_Resource_Landing_Pages(); + + // Initialize warnings array. + $warnings = array(); + + // Form. + if ( $forms->is_legacy( $convertkit_post->get_form() ) ) { + $warnings[] = sprintf( + /* translators: %s: Form name */ + __( 'Form: %s', 'convertkit' ), + $this->get_form_display_name( $convertkit_post->get_form(), $forms ) + ); + } + + // Landing Page. + if ( $landing_pages->is_legacy( $convertkit_post->get_landing_page() ) ) { + $warnings[] = sprintf( + /* translators: %s: Landing page name */ + __( 'Landing Page: %s', 'convertkit' ), + $this->get_landing_page_display_name( $convertkit_post->get_landing_page(), $landing_pages ) + ); + } + + // Restrict Content. + if ( $convertkit_post->get_restrict_content_type() === 'form' && $forms->is_legacy( $convertkit_post->get_restrict_content_id() ) ) { + $warnings[] = sprintf( + /* translators: %s: Form name */ + __( 'Member Content: %s', 'convertkit' ), + $this->get_form_display_name( $convertkit_post->get_restrict_content_id(), $forms ) + ); + } + + return $warnings; + + } + + /** + * Resolves the form ID to a human-readable "Form Name" string, falling + * back to "a Legacy Form" when the resource isn't cached. + * + * @since 3.3.7 + * + * @param int $form_id Form ID. + * @param ConvertKit_Resource_Forms $forms Forms resource class. + * @return string + */ + private function get_form_display_name( $form_id, $forms ) { + + $form = $forms->get_by_id( $form_id ); + if ( $form && ! empty( $form['name'] ) ) { + return sanitize_text_field( $form['name'] ); + } + + return __( 'a Legacy Form', 'convertkit' ); + + } + + /** + * Resolves the landing page identifier (numeric ID or URL string) to a + * human-readable "Landing Page Name" string, falling back to + * "a Legacy Landing Page" when the resource isn't cached. + * + * @since 3.3.7 + * + * @param int|string $id_or_url Landing Page ID or URL. + * @param ConvertKit_Resource_Landing_Pages $landing_pages Landing Pages resource class. + * @return string + */ + private function get_landing_page_display_name( $id_or_url, $landing_pages ) { + + // URL-string legacy assignments (pre-1.9.6) don't have a cached + // resource entry we can look up by ID, so fall back straight away. + if ( is_string( $id_or_url ) && strstr( $id_or_url, 'http' ) ) { + return __( 'a Legacy Landing Page', 'convertkit' ); + } + + $landing_page = $landing_pages->get_by_id( (int) $id_or_url ); + if ( $landing_page && ! empty( $landing_page['name'] ) ) { + return sanitize_text_field( $landing_page['name'] ); + } + + return __( 'a Legacy Landing Page', 'convertkit' ); + + } + + /** + * Returns the current post ID being edited, or 0 if not on a post edit + * screen. Reads $_GET['post'] because $post isn't always set in the + * admin_notices / enqueue_block_editor_assets hook contexts. + * + * @since 3.3.7 + * + * @return int + */ + private function get_current_post_id() { + + // phpcs:ignore WordPress.Security.NonceVerification.Recommended + if ( isset( $_GET['post'] ) ) { + return absint( $_GET['post'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended + } + + return 0; + + } + +} diff --git a/includes/class-wp-convertkit.php b/includes/class-wp-convertkit.php index 371ab59d0..922e466b8 100644 --- a/includes/class-wp-convertkit.php +++ b/includes/class-wp-convertkit.php @@ -83,6 +83,7 @@ private function initialize_admin() { $this->classes['admin_cache_plugins'] = new ConvertKit_Admin_Cache_Plugins(); $this->classes['admin_category'] = new ConvertKit_Admin_Category(); $this->classes['admin_landing_page'] = new ConvertKit_Admin_Landing_Page(); + $this->classes['admin_legacy_resource_notice'] = new ConvertKit_Admin_Legacy_Resource_Notice(); $this->classes['admin_importer_activecampaign'] = new ConvertKit_Admin_Importer_ActiveCampaign(); $this->classes['admin_importer_aweber'] = new ConvertKit_Admin_Importer_AWeber(); $this->classes['admin_importer_campaignmonitor'] = new ConvertKit_Admin_Importer_CampaignMonitor(); diff --git a/resources/backend/js/legacy-resource-notice.js b/resources/backend/js/legacy-resource-notice.js new file mode 100644 index 000000000..cf605d543 --- /dev/null +++ b/resources/backend/js/legacy-resource-notice.js @@ -0,0 +1,49 @@ +/** + * Renders a non-dismissible warning notice inside Gutenberg + * when a post/page references a legacy Kit resource. + * + * @author ConvertKit + * @since 3.3.7 + */ + +document.addEventListener('DOMContentLoaded', function () { + // Bail if the notice data is not available. + if (typeof convertkit_legacy_resource_notice === 'undefined') { + return; + } + + // Bail if no warnings are found. + if ( + typeof convertkit_legacy_resource_notice.warnings === 'undefined' || + convertkit_legacy_resource_notice.warnings.length === 0 + ) { + return; + } + + // Bail if Gutenberg is not available. + if ( + typeof wp === 'undefined' || + typeof wp.data === 'undefined' || + typeof wp.data.dispatch !== 'function' + ) { + return; + } + + // Build the notice. + const message = + convertkit_legacy_resource_notice.intro + + '\n' + + convertkit_legacy_resource_notice.warnings + .map(function (warning) { + return '- ' + warning; + }) + .join('\n'); + + // Create the notice. + wp.data + .dispatch('core/notices') + .createWarningNotice(message, { + id: convertkit_legacy_resource_notice.id, + isDismissible: false, + }); +}); diff --git a/tests/EndToEnd/general/other/BlockEditorLegacyNoticeCest.php b/tests/EndToEnd/general/other/BlockEditorLegacyNoticeCest.php new file mode 100644 index 000000000..c6d71c988 --- /dev/null +++ b/tests/EndToEnd/general/other/BlockEditorLegacyNoticeCest.php @@ -0,0 +1,237 @@ +activateKitPlugin($I); + $I->setupKitPlugin($I); + $I->setupKitPluginResources($I); + } + + /** + * Test that a page with a legacy Form assignment displays the warning + * notice inside Gutenberg, listing the legacy form by name. + * + * @since 3.3.7 + * + * @param EndToEndTester $I Tester. + */ + public function testNoticeDisplaysForLegacyForm(EndToEndTester $I) + { + // Create a page with a Legacy Form assignment. + $pageID = $I->havePageInDatabase( + [ + 'post_status' => 'publish', + 'post_title' => 'Kit: Legacy Notice: Gutenberg: Form', + 'meta_input' => [ + '_wp_convertkit_post_meta' => [ + 'form' => (string) $_ENV['CONVERTKIT_API_LEGACY_FORM_ID'], + 'landing_page' => '', + 'tag' => '', + ], + ], + ] + ); + + // Navigate to the page and wait for the notice to appear. + $I->amOnAdminPage('post.php?post=' . $pageID . '&action=edit'); + $I->waitForElementVisible($this->noticeSelector); + + // Assert the notice displays the legacy form by name. + $I->see('Form: ' . $_ENV['CONVERTKIT_API_LEGACY_FORM_NAME'], $this->noticeSelector); + + // Assert the notice does not have a dismiss button. + $I->dontSeeElementInDOM($this->noticeSelector . ' button.components-notice__dismiss'); + } + + /** + * Test that a page with a legacy Landing Page assignment displays the + * warning notice inside Gutenberg, listing the legacy landing page by + * name. + * + * @since 3.3.7 + * + * @param EndToEndTester $I Tester. + */ + public function testNoticeDisplaysForLegacyLandingPage(EndToEndTester $I) + { + // Create a page with a Legacy Landing Page assignment. + $pageID = $I->havePageInDatabase( + [ + 'post_status' => 'publish', + 'post_title' => 'Kit: Legacy Notice: Gutenberg: Landing Page', + 'meta_input' => [ + '_wp_convertkit_post_meta' => [ + 'form' => '0', + 'landing_page' => (string) $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_ID'], + 'tag' => '', + ], + ], + ] + ); + + // Navigate to the page and wait for the notice to appear. + $I->amOnAdminPage('post.php?post=' . $pageID . '&action=edit'); + $I->waitForElementVisible($this->noticeSelector); + + // Assert the notice displays the legacy landing page by name. + $I->see('Landing Page: ' . $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_NAME'], $this->noticeSelector); + + // Assert the notice does not have a dismiss button. + $I->dontSeeElementInDOM($this->noticeSelector . ' button.components-notice__dismiss'); + } + + /** + * Test that a page with a Restrict Content assignment referencing a + * legacy Kit form displays the warning notice inside Gutenberg, scoped + * to Member Content. + * + * @since 3.3.7 + * + * @param EndToEndTester $I Tester. + */ + public function testNoticeDisplaysForLegacyRestrictContentForm(EndToEndTester $I) + { + // Create a page with a Restrict Content assignment referencing a + // legacy Kit form. + $pageID = $I->havePageInDatabase( + [ + 'post_status' => 'publish', + 'post_title' => 'Kit: Legacy Notice: Gutenberg: Restrict Content', + 'meta_input' => [ + '_wp_convertkit_post_meta' => [ + 'form' => '0', + 'landing_page' => '', + 'tag' => '', + 'restrict_content' => 'form_' . $_ENV['CONVERTKIT_API_LEGACY_FORM_ID'], + ], + ], + ] + ); + + // Navigate to the page and wait for the notice to appear. + $I->amOnAdminPage('post.php?post=' . $pageID . '&action=edit'); + $I->waitForElementVisible($this->noticeSelector); + + // Assert the notice displays the legacy form by name. + $I->see('Member Content: ' . $_ENV['CONVERTKIT_API_LEGACY_FORM_NAME'], $this->noticeSelector); + + // Assert the notice does not have a dismiss button. + $I->dontSeeElementInDOM($this->noticeSelector . ' button.components-notice__dismiss'); + } + + /** + * Test that a page assigning only v4 Kit resources does not display + * the legacy warning notice inside Gutenberg. + * + * @since 3.3.7 + * + * @param EndToEndTester $I Tester. + */ + public function testNoticeDoesNotDisplayForV4Resources(EndToEndTester $I) + { + // Create a page assigning only v4 Kit resources. + $pageID = $I->havePageInDatabase( + [ + 'post_status' => 'publish', + 'post_title' => 'Kit: Legacy Notice: Gutenberg: V4 Only', + 'meta_input' => [ + '_wp_convertkit_post_meta' => [ + 'form' => (string) $_ENV['CONVERTKIT_API_FORM_ID'], + 'landing_page' => (string) $_ENV['CONVERTKIT_API_LANDING_PAGE_ID'], + 'tag' => '', + ], + ], + ] + ); + + // Navigate to the page and wait for Gutenberg to settle. + $I->amOnAdminPage('post.php?post=' . $pageID . '&action=edit'); + + // Assert the notice is not present. + $I->waitForElementVisible('.block-editor'); + $I->dontSeeElementInDOM($this->noticeSelector); + } + + /** + * Test that a page with legacy form + legacy landing page + legacy + * Member Content assignments displays a single consolidated warning + * notice inside Gutenberg with all three items listed. + * + * @since 3.3.7 + * + * @param EndToEndTester $I Tester. + */ + public function testConsolidatedNoticeWhenMultipleLegacy(EndToEndTester $I) + { + // Create a page with legacy form + legacy landing page + legacy + // Member Content assignments. + $pageID = $I->havePageInDatabase( + [ + 'post_status' => 'publish', + 'post_title' => 'Kit: Legacy Notice: Gutenberg: Consolidated', + 'meta_input' => [ + '_wp_convertkit_post_meta' => [ + 'form' => (string) $_ENV['CONVERTKIT_API_LEGACY_FORM_ID'], + 'landing_page' => (string) $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_ID'], + 'tag' => '', + 'restrict_content' => 'form_' . $_ENV['CONVERTKIT_API_LEGACY_FORM_ID'], + ], + ], + ] + ); + + // Navigate to the page and wait for the notice to appear. + $I->amOnAdminPage('post.php?post=' . $pageID . '&action=edit'); + $I->waitForElementVisible($this->noticeSelector); + + // Assert the notice displays all three legacy resources. + $I->seeNumberOfElementsInDOM($this->noticeSelector, 1); + $I->see('Form: ' . $_ENV['CONVERTKIT_API_LEGACY_FORM_NAME'], $this->noticeSelector); + $I->see('Landing Page: ' . $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_NAME'], $this->noticeSelector); + $I->see('Member Content: ' . $_ENV['CONVERTKIT_API_LEGACY_FORM_NAME'], $this->noticeSelector); + } + + /** + * Deactivate and reset Plugin(s) after each test, if the test passes. + * We don't use _after, as this would provide a screenshot of the Plugin + * deactivation and not the true test error. + * + * @since 3.3.7 + * + * @param EndToEndTester $I Tester. + */ + public function _passed(EndToEndTester $I) + { + $I->deactivateKitPlugin($I); + $I->resetKitPlugin($I); + } +} diff --git a/tests/EndToEnd/general/other/ClassicEditorLegacyNoticeCest.php b/tests/EndToEnd/general/other/ClassicEditorLegacyNoticeCest.php new file mode 100644 index 000000000..91040f2bf --- /dev/null +++ b/tests/EndToEnd/general/other/ClassicEditorLegacyNoticeCest.php @@ -0,0 +1,239 @@ +activateKitPlugin($I); + $I->activateThirdPartyPlugin($I, 'classic-editor'); + $I->setupKitPlugin($I); + $I->setupKitPluginResources($I); + } + + /** + * Test that a page with a legacy Form assignment displays the warning + * notice on the classic editor, listing the legacy form by name. + * + * @since 3.3.7 + * + * @param EndToEndTester $I Tester. + */ + public function testNoticeDisplaysForLegacyForm(EndToEndTester $I) + { + // Create a page with a Legacy Form assignment. + $pageID = $I->havePageInDatabase( + [ + 'post_status' => 'publish', + 'post_title' => 'Kit: Legacy Notice: Form', + 'meta_input' => [ + '_wp_convertkit_post_meta' => [ + 'form' => (string) $_ENV['CONVERTKIT_API_LEGACY_FORM_ID'], + 'landing_page' => '', + 'tag' => '', + ], + ], + ] + ); + + // Navigate to the page and wait for the notice to appear. + $I->amOnAdminPage('post.php?post=' . $pageID . '&action=edit'); + $I->seeElementInDOM($this->noticeSelector); + + // Assert the notice displays the legacy form by name. + $I->see('Form: ' . $_ENV['CONVERTKIT_API_LEGACY_FORM_NAME'], $this->noticeSelector); + + // Assert the notice does not have a dismiss button. + $I->dontSeeElementInDOM($this->noticeSelector . ' button.notice-dismiss'); + } + + /** + * Test that a page with a legacy Landing Page assignment displays the + * warning notice on the classic editor, listing the legacy landing + * page by name. + * + * @since 3.3.7 + * + * @param EndToEndTester $I Tester. + */ + public function testNoticeDisplaysForLegacyLandingPage(EndToEndTester $I) + { + // Create a page with a Legacy Landing Page assignment. + $pageID = $I->havePageInDatabase( + [ + 'post_status' => 'publish', + 'post_title' => 'Kit: Legacy Notice: Landing Page', + 'meta_input' => [ + '_wp_convertkit_post_meta' => [ + 'form' => '0', + 'landing_page' => (string) $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_ID'], + 'tag' => '', + ], + ], + ] + ); + + // Navigate to the page and wait for the notice to appear. + $I->amOnAdminPage('post.php?post=' . $pageID . '&action=edit'); + $I->seeElementInDOM($this->noticeSelector); + + // Assert the notice displays the legacy landing page by name. + $I->see('Landing Page: ' . $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_NAME'], $this->noticeSelector); + + // Assert the notice does not have a dismiss button. + $I->dontSeeElementInDOM($this->noticeSelector . ' button.notice-dismiss'); + } + + /** + * Test that a page with a Restrict Content assignment referencing a + * legacy Kit form displays the warning notice on the classic editor, + * scoped to Member Content. + * + * @since 3.3.7 + * + * @param EndToEndTester $I Tester. + */ + public function testNoticeDisplaysForLegacyRestrictContentForm(EndToEndTester $I) + { + // Create a page with a Restrict Content assignment referencing a + // legacy Kit form. + $pageID = $I->havePageInDatabase( + [ + 'post_status' => 'publish', + 'post_title' => 'Kit: Legacy Notice: Restrict Content', + 'meta_input' => [ + '_wp_convertkit_post_meta' => [ + 'form' => '0', + 'landing_page' => '', + 'tag' => '', + 'restrict_content' => 'form_' . $_ENV['CONVERTKIT_API_LEGACY_FORM_ID'], + ], + ], + ] + ); + + // Navigate to the page and wait for the notice to appear. + $I->amOnAdminPage('post.php?post=' . $pageID . '&action=edit'); + $I->seeElementInDOM($this->noticeSelector); + + // Assert the notice displays the legacy form by name. + $I->see('Member Content: ' . $_ENV['CONVERTKIT_API_LEGACY_FORM_NAME'], $this->noticeSelector); + + // Assert the notice does not have a dismiss button. + $I->dontSeeElementInDOM($this->noticeSelector . ' button.notice-dismiss'); + } + + /** + * Test that a page assigning only v4 Kit resources does not display + * the legacy warning notice. + * + * @since 3.3.7 + * + * @param EndToEndTester $I Tester. + */ + public function testNoticeDoesNotDisplayForV4Resources(EndToEndTester $I) + { + // Create a page assigning only v4 Kit resources. + $pageID = $I->havePageInDatabase( + [ + 'post_status' => 'publish', + 'post_title' => 'Kit: Legacy Notice: V4 Only', + 'meta_input' => [ + '_wp_convertkit_post_meta' => [ + 'form' => (string) $_ENV['CONVERTKIT_API_FORM_ID'], + 'landing_page' => (string) $_ENV['CONVERTKIT_API_LANDING_PAGE_ID'], + 'tag' => '', + ], + ], + ] + ); + + // Navigate to the page and wait for the notice to appear. + $I->amOnAdminPage('post.php?post=' . $pageID . '&action=edit'); + + // Assert the notice is not present. + $I->dontSee('Kit: This page uses one or more legacy Kit resources'); + } + + /** + * Test that a page with legacy form + legacy landing page + legacy + * Member Content assignments displays a single consolidated warning + * notice with all three items listed. + * + * @since 3.3.7 + * + * @param EndToEndTester $I Tester. + */ + public function testConsolidatedNoticeWhenMultipleLegacyResources(EndToEndTester $I) + { + // Create a page with legacy form + legacy landing page + legacy + // Member Content assignments. + $pageID = $I->havePageInDatabase( + [ + 'post_status' => 'publish', + 'post_title' => 'Kit: Legacy Notice: Consolidated', + 'meta_input' => [ + '_wp_convertkit_post_meta' => [ + 'form' => (string) $_ENV['CONVERTKIT_API_LEGACY_FORM_ID'], + 'landing_page' => (string) $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_ID'], + 'tag' => '', + 'restrict_content' => 'form_' . $_ENV['CONVERTKIT_API_LEGACY_FORM_ID'], + ], + ], + ] + ); + + // Navigate to the page and wait for the notice to appear. + $I->amOnAdminPage('post.php?post=' . $pageID . '&action=edit'); + + // Assert the notice displays all three legacy resources. + $I->seeNumberOfElementsInDOM($this->noticeSelector, 1); + $I->see('Form: ' . $_ENV['CONVERTKIT_API_LEGACY_FORM_NAME'], $this->noticeSelector); + + // Assert the notice displays the legacy landing page by name. + $I->see('Landing Page: ' . $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_NAME'], $this->noticeSelector); + $I->see('Member Content: ' . $_ENV['CONVERTKIT_API_LEGACY_FORM_NAME'], $this->noticeSelector); + } + + /** + * Deactivate and reset Plugin(s) after each test, if the test passes. + * We don't use _after, as this would provide a screenshot of the Plugin + * deactivation and not the true test error. + * + * @since 3.3.7 + * + * @param EndToEndTester $I Tester. + */ + public function _passed(EndToEndTester $I) + { + $I->deactivateThirdPartyPlugin($I, 'classic-editor'); + $I->deactivateKitPlugin($I); + $I->resetKitPlugin($I); + } +} diff --git a/tests/Integration/AdminLegacyResourceNoticeTest.php b/tests/Integration/AdminLegacyResourceNoticeTest.php new file mode 100644 index 000000000..26ac6bbe8 --- /dev/null +++ b/tests/Integration/AdminLegacyResourceNoticeTest.php @@ -0,0 +1,228 @@ + $_ENV['CONVERTKIT_OAUTH_ACCESS_TOKEN'], + 'refresh_token' => $_ENV['CONVERTKIT_OAUTH_REFRESH_TOKEN'], + ] + ); + + // Refresh Forms and Landing Pages resources so is_legacy() calls resolve + // correctly against the API-backed cache. + $forms = new \ConvertKit_Resource_Forms(); + $forms->refresh(); + + $landing_pages = new \ConvertKit_Resource_Landing_Pages(); + $landing_pages->refresh(); + + $this->notice = new \ConvertKit_Admin_Legacy_Resource_Notice(); + } + + /** + * Test that a settings array with only v4 resource assignments returns + * no warnings. + * + * @since 3.3.7 + */ + public function testNoWarningsForV4Resources() + { + $warnings = $this->notice->get_legacy_warnings_for_post_settings( + [ + 'form' => $_ENV['CONVERTKIT_API_FORM_ID'], + 'landing_page' => $_ENV['CONVERTKIT_API_LANDING_PAGE_ID'], + 'restrict_content' => 'form_' . $_ENV['CONVERTKIT_API_FORM_ID'], + ] + ); + + $this->assertSame([], $warnings); + } + + /** + * Test that a legacy form assignment produces a form-scoped warning + * containing the form's name. + * + * @since 3.3.7 + */ + public function testWarningForLegacyForm() + { + $warnings = $this->notice->get_legacy_warnings_for_post_settings( + [ + 'form' => $_ENV['CONVERTKIT_API_LEGACY_FORM_ID'], + ] + ); + + $this->assertCount(1, $warnings); + $this->assertStringContainsString('Form:', $warnings[0]); + $this->assertStringContainsString($_ENV['CONVERTKIT_API_LEGACY_FORM_NAME'], $warnings[0]); + } + + /** + * Test that a legacy landing page assignment (by numeric ID) produces + * a landing-page-scoped warning containing the landing page's name. + * + * @since 3.3.7 + */ + public function testWarningForLegacyLandingPageByID() + { + $warnings = $this->notice->get_legacy_warnings_for_post_settings( + [ + 'landing_page' => $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_ID'], + ] + ); + + $this->assertCount(1, $warnings); + $this->assertStringContainsString('Landing Page:', $warnings[0]); + $this->assertStringContainsString($_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_NAME'], $warnings[0]); + } + + /** + * Test that a legacy landing page assignment stored as a URL string + * (pre-1.9.6 storage) produces a landing-page-scoped warning using the + * fallback label since we can't resolve a name from the URL alone. + * + * @since 3.3.7 + */ + public function testWarningForLegacyLandingPageByURL() + { + $warnings = $this->notice->get_legacy_warnings_for_post_settings( + [ + 'landing_page' => $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_URL'], + ] + ); + + $this->assertCount(1, $warnings); + $this->assertStringContainsString('Landing Page:', $warnings[0]); + $this->assertStringContainsString('a Legacy Landing Page', $warnings[0]); + } + + /** + * Test that a restrict_content value of `form_` produces a + * Member Content warning. + * + * @since 3.3.7 + */ + public function testWarningForLegacyRestrictContentForm() + { + $warnings = $this->notice->get_legacy_warnings_for_post_settings( + [ + 'restrict_content' => 'form_' . $_ENV['CONVERTKIT_API_LEGACY_FORM_ID'], + ] + ); + + $this->assertCount(1, $warnings); + $this->assertStringContainsString('Member Content:', $warnings[0]); + $this->assertStringContainsString($_ENV['CONVERTKIT_API_LEGACY_FORM_NAME'], $warnings[0]); + } + + /** + * Test that restrict_content values of `tag_` and `product_` + * never trigger a warning, because tags and products have no legacy + * variant. + * + * @since 3.3.7 + */ + public function testNoWarningForLegacyRestrictContentTagOrProduct() + { + $tag = $this->notice->get_legacy_warnings_for_post_settings( + [ + 'restrict_content' => 'tag_' . $_ENV['CONVERTKIT_API_TAG_ID'], + ] + ); + $product = $this->notice->get_legacy_warnings_for_post_settings( + [ + 'restrict_content' => 'product_1', + ] + ); + + $this->assertSame([], $tag); + $this->assertSame([], $product); + } + + /** + * Test that a settings array with legacy form + legacy landing page + + * legacy restrict_content form produces three warnings in a single + * returned array. + * + * @since 3.3.7 + */ + public function testWarningsForMultipleLegacyResources() + { + $warnings = $this->notice->get_legacy_warnings_for_post_settings( + [ + 'form' => $_ENV['CONVERTKIT_API_LEGACY_FORM_ID'], + 'landing_page' => $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_ID'], + 'restrict_content' => 'form_' . $_ENV['CONVERTKIT_API_LEGACY_FORM_ID'], + ] + ); + + $this->assertCount(3, $warnings); + } + + /** + * Test that when a legacy form ID doesn't resolve to any cached resource + * (e.g. the form was deleted from the Kit account), the warning falls + * back to "a Legacy Form" rather than omitting the entry. + * + * @since 3.3.7 + */ + public function testWarningWithMissingResourceFallsBackToLabel() + { + // Wipe the Forms cache so is_legacy() can no longer resolve any + // numeric ID to a real resource. is_legacy() will therefore return + // false for numeric IDs — but a URL-based landing page assignment + // still resolves as legacy by the URL-string check, exercising the + // name-fallback path. + delete_option('convertkit_forms'); + delete_option('convertkit_landing_pages'); + + $warnings = $this->notice->get_legacy_warnings_for_post_settings( + [ + 'landing_page' => $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_URL'], + ] + ); + + $this->assertCount(1, $warnings); + $this->assertStringContainsString('a Legacy Landing Page', $warnings[0]); + } +} diff --git a/wp-convertkit.php b/wp-convertkit.php index caead13e1..a400ce5fd 100644 --- a/wp-convertkit.php +++ b/wp-convertkit.php @@ -111,6 +111,7 @@ require_once CONVERTKIT_PLUGIN_PATH . '/admin/class-convertkit-admin-cache-plugins.php'; require_once CONVERTKIT_PLUGIN_PATH . '/admin/class-convertkit-admin-category.php'; require_once CONVERTKIT_PLUGIN_PATH . '/admin/class-convertkit-admin-landing-page.php'; +require_once CONVERTKIT_PLUGIN_PATH . '/admin/class-convertkit-admin-legacy-resource-notice.php'; require_once CONVERTKIT_PLUGIN_PATH . '/admin/class-convertkit-admin-post.php'; require_once CONVERTKIT_PLUGIN_PATH . '/admin/class-convertkit-admin-refresh-resources.php'; require_once CONVERTKIT_PLUGIN_PATH . '/admin/class-convertkit-admin-restrict-content.php';