diff --git a/includes/class-convertkit-resource-landing-pages.php b/includes/class-convertkit-resource-landing-pages.php index 642f5deb5..bda4af770 100644 --- a/includes/class-convertkit-resource-landing-pages.php +++ b/includes/class-convertkit-resource-landing-pages.php @@ -56,6 +56,84 @@ public function __construct( $context = 'landing_pages' ) { } + /** + * Returns all non-legacy landing pages (v4 pages with an `embed_url` + * property). Legacy landing pages have a `url` property instead and are + * excluded here. + * + * @since 3.3.7 + * + * @return bool|array + */ + public function get_non_legacy() { + + $resources = $this->get(); + if ( ! $resources ) { + return false; + } + + $non_legacy = array(); + foreach ( $resources as $id => $landing_page ) { + if ( isset( $landing_page['url'] ) ) { + continue; + } + $non_legacy[ $id ] = $landing_page; + } + + return $non_legacy; + + } + + /** + * Returns whether any non-legacy landing pages exist in the options table. + * + * @since 3.3.7 + * + * @return bool + */ + public function non_legacy_exist() { + + return (bool) $this->get_non_legacy(); + + } + + /** + * Determines whether the given identifier refers to a legacy landing page. + * + * Handles both storage shapes: a URL string (as saved by Plugin versions + * < 1.9.6 which stored the landing page URL directly on the post), and a + * numeric ID that resolves to a resource entry containing a `url` key. + * + * @since 3.3.7 + * + * @param int|string $id_or_url Landing Page ID or URL. + * @return bool + */ + public function is_legacy( $id_or_url ) { + + // Bail if no value. + if ( ! $id_or_url ) { + return false; + } + + // If the value is a URL string, it's a legacy landing page as stored + // by Plugin versions < 1.9.6. + if ( is_string( $id_or_url ) && strstr( $id_or_url, 'http' ) ) { + return true; + } + + // Otherwise resolve the ID against the cached resources. + $landing_page = $this->get_by_id( (int) $id_or_url ); + + if ( ! $landing_page ) { + return false; + } + + // Legacy landing pages carry a `url` key; v4 pages carry `embed_url`. + return isset( $landing_page['url'] ); + + } + /** * Returns the HTML/JS markup for the given Landing Page ID * diff --git a/includes/plugin-sidebars/class-convertkit-plugin-sidebar-post-settings.php b/includes/plugin-sidebars/class-convertkit-plugin-sidebar-post-settings.php index bd68e3a06..36ceadbc7 100644 --- a/includes/plugin-sidebars/class-convertkit-plugin-sidebar-post-settings.php +++ b/includes/plugin-sidebars/class-convertkit-plugin-sidebar-post-settings.php @@ -145,13 +145,21 @@ public function get_fields() { } } - // Get Landing Pages. - $landing_pages = array( + // Get Landing Pages. Non-legacy pages populate the dropdown; legacy + // pages are exposed separately as a fallback so a previously-saved + // legacy landing page remains visible as the current selection + // without offering other legacy pages as new choices. + $landing_pages = array( '0' => esc_html__( 'None', 'convertkit' ), ); + $legacy_landing_pages = array(); if ( $convertkit_landing_pages->exist() ) { foreach ( $convertkit_landing_pages->get() as $landing_page ) { - $landing_pages[ absint( $landing_page['id'] ) ] = sanitize_text_field( $landing_page['name'] ); + if ( isset( $landing_page['url'] ) ) { + $legacy_landing_pages[ absint( $landing_page['id'] ) ] = sanitize_text_field( $landing_page['name'] ); + } else { + $landing_pages[ absint( $landing_page['id'] ) ] = sanitize_text_field( $landing_page['name'] ); + } } } @@ -251,6 +259,7 @@ public function get_fields() { ), ), 'values' => $landing_pages, + 'legacy_values' => $legacy_landing_pages, 'post_type' => 'page', 'resource_type' => 'landing_pages', ), diff --git a/tests/EndToEnd/landing-pages/BlockEditorLandingPageCest.php b/tests/EndToEnd/landing-pages/BlockEditorLandingPageCest.php index bdd82bf29..b210fd1e0 100644 --- a/tests/EndToEnd/landing-pages/BlockEditorLandingPageCest.php +++ b/tests/EndToEnd/landing-pages/BlockEditorLandingPageCest.php @@ -173,83 +173,6 @@ public function testLandingPageCharacterEncoding(EndToEndTester $I) $I->seeInSource('Vantar þinn ungling sjálfstraust í stærðfræði?'); } - /** - * Test that the Legacy Landing Page specified in the Page Settings works when - * creating and viewing a new WordPress Page. - * - * @since 1.9.6.3 - * - * @param EndToEndTester $I Tester. - */ - public function testAddNewPageUsingDefinedLegacyLandingPage(EndToEndTester $I) - { - // Add a Page using the Gutenberg editor. - $I->addGutenbergPage( - $I, - title: 'Kit: Page: Landing Page: ' . $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_NAME'] - ); - - // Configure metabox's Landing Page setting to value specified in the .env file. - $I->configurePluginSidebarSettings( - $I, - landingPage: $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_NAME'] - ); - - // Publish and view the Page on the frontend site. - $I->publishAndViewGutenbergPage($I); - - // Confirm that the basic HTML structure is correct. - $I->seeLandingPageOutput($I); - - // Confirm that the Kit Landing Page displays. - $I->dontSeeElementInDOM('body.page'); // WordPress didn't load its template, which is correct. - $I->seeInSource('
'); // Kit injected its Landing Page Form, which is correct. - } - - /** - * Test that the WordPress site icon is output as the favicon on a Legacy Landing Page, - * when defined. - * - * @since 2.3.0 - * - * @param EndToEndTester $I Tester. - */ - public function testLegacyLandingPageSiteIcon(EndToEndTester $I) - { - // Define a WordPress Site Icon. - $imageID = $I->haveAttachmentInDatabase(codecept_data_dir('icon.png')); - $I->haveOptionInDatabase('site_icon', $imageID); - - // Add a Page using the Gutenberg editor. - $I->addGutenbergPage( - $I, - title: 'Kit: Page: Legacy Landing Page: Site Icon: ' . $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_NAME'] - ); - - // Configure metabox's Landing Page setting to value specified in the .env file. - $I->configurePluginSidebarSettings( - $I, - landingPage: $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_NAME'] - ); - - // Publish and view the Page on the frontend site. - $I->publishAndViewGutenbergPage($I); - - // Confirm that the basic HTML structure is correct. - $I->seeLandingPageOutput($I); - - // Confirm the WordPress Site Icon displays. - $I->seeInSource(''); - $I->seeInSource(''); - $I->seeInSource(''); - $I->seeInSource(''); - $I->dontSeeInSource(''); - - // Confirm that the Kit Landing Page displays. - $I->dontSeeElementInDOM('body.page'); // WordPress didn't load its template, which is correct. - $I->seeInSource(''); // Kit injected its Landing Page Form, which is correct. - } - /** * Test that the Legacy Landing Page specified in the Page Settings works when * the Landing Page was defined by the Kit Plugin < 1.9.6, which used a URL @@ -572,6 +495,73 @@ public function testAddNewPostDoesNotDisplayLandingPageOption(EndToEndTester $I) $I->publishGutenbergPage($I); } + /** + * Test that the Gutenberg plugin sidebar's Landing Page dropdown does not + * offer legacy landing pages as a selection option. + * + * @since 3.3.7 + * + * @param EndToEndTester $I Tester. + */ + public function testLegacyLandingPagesExcludedFromPluginSidebar(EndToEndTester $I) + { + // Add a Page using the Gutenberg editor. + $I->addGutenbergPage( + $I, + title: 'Kit: Page: No Legacy Landing Pages In Plugin Sidebar' + ); + + // Open the Plugin sidebar so the Landing Page dropdown renders. + $I->openPluginSidebarSettings($I); + $landingPageSelectXPath = '//label[text()="Landing Page"]/following::select[1]'; + $I->waitForElementVisible($landingPageSelectXPath); + $I->dontSee( + $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_NAME'], + $landingPageSelectXPath + ); + } + + /** + * Test that a Page preseeded with a legacy landing page ID in its post + * meta continues to display that legacy landing page as the selected + * option in the Gutenberg plugin sidebar. + * + * @since 3.3.7 + * + * @param EndToEndTester $I Tester. + */ + public function testPluginSidebarPreservesSelectedLegacyLandingPage(EndToEndTester $I) + { + // Preseed a Page with a legacy landing page ID in its Kit post meta. + $pageID = $I->havePageInDatabase( + [ + 'post_type' => 'page', + 'post_status' => 'publish', + 'post_title' => 'Kit: Page: Plugin Sidebar Preserves Legacy Landing Page', + 'post_name' => 'kit-plugin-sidebar-preserves-legacy-landing-page', + 'meta_input' => [ + '_wp_convertkit_post_meta' => [ + 'form' => '0', + 'landing_page' => (string) $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_ID'], + 'tag' => '', + ], + ], + ] + ); + + // Open the Gutenberg edit screen and the Plugin sidebar. Confirm the + // legacy landing page is the selected option, even though it is no + // longer offered as a new selection choice. + $I->amOnAdminPage('post.php?post=' . $pageID . '&action=edit'); + $I->openPluginSidebarSettings($I); + $landingPageSelectXPath = '//label[text()="Landing Page"]/following::select[1]'; + $I->waitForElementVisible($landingPageSelectXPath); + $I->seeOptionIsSelected( + $landingPageSelectXPath, + $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_NAME'] + ); + } + /** * 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 diff --git a/tests/EndToEnd/landing-pages/ClassicEditorLandingPageCest.php b/tests/EndToEnd/landing-pages/ClassicEditorLandingPageCest.php index a38dedc22..39ac25867 100644 --- a/tests/EndToEnd/landing-pages/ClassicEditorLandingPageCest.php +++ b/tests/EndToEnd/landing-pages/ClassicEditorLandingPageCest.php @@ -188,89 +188,6 @@ public function testLandingPageCharacterEncoding(EndToEndTester $I) $I->seeInSource('Vantar þinn ungling sjálfstraust í stærðfræði?'); } - /** - * Test that the Legacy Landing Page specified in the Page Settings works when - * creating and viewing a new WordPress Page. - * - * @since 3.3.0 - * - * @param EndToEndTester $I Tester. - */ - public function testAddNewPageUsingDefinedLegacyLandingPage(EndToEndTester $I) - { - // Add a Page using the Classic Editor. - $I->addClassicEditorPage( - $I, - title: 'Kit: Page: Landing Page: ' . $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_NAME'] - ); - - // Configure metabox's Landing Page setting to value specified in the .env file. - $I->configureMetaboxSettings( - $I, - metabox: 'wp-convertkit-meta-box', - configuration: [ - 'landing_page' => [ 'select2', $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_NAME'] ], - ] - ); - - // Publish and view the Page on the frontend site. - $I->publishAndViewClassicEditorPage($I); - - // Confirm that the basic HTML structure is correct. - $I->seeLandingPageOutput($I); - - // Confirm that the Kit Landing Page displays. - $I->dontSeeElementInDOM('body.page'); // WordPress didn't load its template, which is correct. - $I->seeInSource(''); // Kit injected its Landing Page Form, which is correct. - } - - /** - * Test that the WordPress site icon is output as the favicon on a Legacy Landing Page, - * when defined. - * - * @since 3.3.0 - * - * @param EndToEndTester $I Tester. - */ - public function testLegacyLandingPageSiteIcon(EndToEndTester $I) - { - // Define a WordPress Site Icon. - $imageID = $I->haveAttachmentInDatabase(codecept_data_dir('icon.png')); - $I->haveOptionInDatabase('site_icon', $imageID); - - // Add a Page using the Classic Editor. - $I->addClassicEditorPage( - $I, - title: 'Kit: Page: Legacy Landing Page: Site Icon: ' . $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_NAME'] - ); - - // Configure metabox's Landing Page setting to value specified in the .env file. - $I->configureMetaboxSettings( - $I, - metabox: 'wp-convertkit-meta-box', - configuration: [ - 'landing_page' => [ 'select2', $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_NAME'] ], - ] - ); - - // Publish and view the Page on the frontend site. - $I->publishAndViewClassicEditorPage($I); - - // Confirm that the basic HTML structure is correct. - $I->seeLandingPageOutput($I); - - // Confirm the WordPress Site Icon displays. - $I->seeInSource(''); - $I->seeInSource(''); - $I->seeInSource(''); - $I->seeInSource(''); - $I->dontSeeInSource(''); - - // Confirm that the Kit Landing Page displays. - $I->dontSeeElementInDOM('body.page'); // WordPress didn't load its template, which is correct. - $I->seeInSource(''); // Kit injected its Landing Page Form, which is correct. - } - /** * Test that the Legacy Landing Page specified in the Page Settings works when * the Landing Page was defined by the Kit Plugin < 1.9.6, which used a URL @@ -605,6 +522,124 @@ public function testAddNewPostDoesNotDisplayLandingPageOption(EndToEndTester $I) $I->dontSeeElementInDOM('form[data-sv-form]'); } + /** + * Test that the Post metabox Landing Page dropdown does not offer legacy + * landing pages as a selection option. + * + * @since 3.3.7 + * + * @param EndToEndTester $I Tester. + */ + public function testLegacyLandingPagesExcludedFromMetaboxDropdown(EndToEndTester $I) + { + // Add a Page using the Classic Editor. + $I->amOnAdminPage('post-new.php?post_type=page'); + + // The metabox Landing Page dropdown should not offer the legacy page + // as an option. + $I->dontSeeElementInDOM('#wp-convertkit-landing_page option[value="' . $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_ID'] . '"]'); + $I->dontSee( + $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_NAME'], + '#wp-convertkit-landing_page' + ); + } + + /** + * Test that a Page preseeded with a legacy landing page ID in its post + * meta continues to display that legacy landing page as the selected + * option in the Classic editor metabox, and continues to render the + * legacy landing page on the frontend. + * + * Also asserts that the WordPress site icon replaces the Kit favicon on + * a legacy landing page, previously covered by the deleted + * `testLegacyLandingPageSiteIcon` test that selected the legacy page + * from the dropdown. + * + * @since 3.3.7 + * + * @param EndToEndTester $I Tester. + */ + public function testMetaboxPreservesSelectedLegacyLandingPageByID(EndToEndTester $I) + { + // Define a WordPress Site Icon so the favicon-replacement assertion + // below has something to match. + $imageID = $I->haveAttachmentInDatabase(codecept_data_dir('icon.png')); + $I->haveOptionInDatabase('site_icon', $imageID); + + // Preseed a Page with a legacy landing page ID in its Kit post meta. + $pageID = $I->havePageInDatabase( + [ + 'post_type' => 'page', + 'post_status' => 'publish', + 'post_title' => 'Kit: Page: Preserves Legacy Landing Page ID', + 'post_name' => 'kit-preserves-legacy-landing-page-id', + 'meta_input' => [ + '_wp_convertkit_post_meta' => [ + 'form' => '0', + 'landing_page' => (string) $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_ID'], + 'tag' => '', + ], + ], + ] + ); + + // Open the edit screen and confirm the legacy landing page shows as + // the selected option in the metabox dropdown, even though it is no + // longer offered as a new selection choice. + $I->amOnAdminPage('post.php?post=' . $pageID . '&action=edit'); + $I->seeElementInDOM('#wp-convertkit-landing_page option[value="' . $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_ID'] . '"]'); + $I->seeOptionIsSelected( + '#wp-convertkit-landing_page', + $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_NAME'] + ); + + // View the page on the frontend and confirm the legacy landing page + // still renders, including the WordPress site icon replacing the Kit + // favicon. + $I->amOnPage('/?p=' . $pageID); + $I->dontSeeElementInDOM('body.page'); + $I->seeInSource(''); + $I->seeInSource(''); + $I->dontSeeInSource(''); + } + + /** + * Test that a Page preseeded with a legacy landing page URL string in its + * post meta (as saved by Plugin versions < 1.9.6) continues to display + * that legacy landing page as the selected option in the Classic editor + * metabox. + * + * @since 3.3.7 + * + * @param EndToEndTester $I Tester. + */ + public function testMetaboxPreservesSelectedLegacyLandingPageByURL(EndToEndTester $I) + { + // Preseed a Page with a legacy landing page URL string in its Kit + // post meta, mirroring how < 1.9.6 of the Plugin stored the value. + $pageID = $I->havePageInDatabase( + [ + 'post_type' => 'page', + 'post_status' => 'publish', + 'post_title' => 'Kit: Page: Preserves Legacy Landing Page URL', + 'post_name' => 'kit-preserves-legacy-landing-page-url', + 'meta_input' => [ + '_wp_convertkit_post_meta' => [ + 'form' => '0', + 'landing_page' => $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_URL'], + 'tag' => '', + ], + ], + ] + ); + + // Open the edit screen and confirm the legacy landing page shows as + // selected. When stored as a URL, the appended option carries the + // URL as its value. + $I->amOnAdminPage('post.php?post=' . $pageID . '&action=edit'); + $I->seeElementInDOM('#wp-convertkit-landing_page option[value="' . $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_URL'] . '"]'); + } + /** * 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 diff --git a/tests/EndToEnd/landing-pages/PageLandingPageSetupWizardCest.php b/tests/EndToEnd/landing-pages/PageLandingPageSetupWizardCest.php index f4ecfd2e7..af0a795c5 100644 --- a/tests/EndToEnd/landing-pages/PageLandingPageSetupWizardCest.php +++ b/tests/EndToEnd/landing-pages/PageLandingPageSetupWizardCest.php @@ -241,45 +241,26 @@ public function testAddNewLandingPage(EndToEndTester $I) } /** - * Test that the Add New Landing Page generates the expected Page - * and displays the selected Legacy Landing Page. + * Test that the Setup Wizard's Landing Page picker does not offer legacy + * landing pages as a selection option. * - * @since 2.5.5 + * @since 3.3.7 * * @param EndToEndTester $I Tester. */ - public function testAddNewLegacyLandingPage(EndToEndTester $I) + public function testLegacyLandingPagesExcludedFromSetupWizard(EndToEndTester $I) { // Setup Plugin and navigate to Add New Landing Page screen. $this->_setupAndLoadAddNewLandingPageScreen($I); - // Select a landing page and enter a slug. - $I->fillSelect2Field( - $I, - container: '#select2-landing_page-container', - value: $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_NAME'] + // The Setup Wizard's landing page dropdown should not offer the + // legacy landing page as an option. + $I->waitForElementVisible('#landing_page'); + $I->dontSeeElementInDOM('#landing_page option[value="' . $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_ID'] . '"]'); + $I->dontSee( + $_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_NAME'], + '#landing_page' ); - $I->fillField('post_name', 'landing-page-setup-wizard'); - - // Click create button. - $I->click('Create'); - - // Confirm that setup completed. - $I->waitForElementVisible('div.convertkit-setup-wizard-grid'); - $I->see('Setup complete'); - - // Click the button to view the landing page. - $I->click('View landing page'); - - // Wait for the Landing Page to load. - $I->waitForElementNotVisible('body.convertkit'); - - // Confirm that the basic HTML structure is correct. - $I->seeLandingPageOutput($I); - - // Confirm that the Kit Landing Page displays. - $I->dontSeeElementInDOM('body.page'); // WordPress didn't load its template, which is correct. - $I->seeInSource(''); // Kit injected its Landing Page Form, which is correct. } /** diff --git a/tests/Integration/ResourceLandingPagesTest.php b/tests/Integration/ResourceLandingPagesTest.php index bb1624fc0..8ed0841b6 100644 --- a/tests/Integration/ResourceLandingPagesTest.php +++ b/tests/Integration/ResourceLandingPagesTest.php @@ -279,4 +279,82 @@ public function testGetHTMLWithLegacyLandingPageID() $this->assertNotInstanceOf(\WP_Error::class, $result); $this->assertStringContainsString('', $result); } + + /** + * Test that get_non_legacy() returns v4 landing pages and excludes legacy + * pages (identified by the presence of a `url` key). + * + * @since 3.3.7 + */ + public function testGetNonLegacy() + { + $result = $this->resource->get_non_legacy(); + + $this->assertIsArray($result); + + // v4 landing pages should be present. + $this->assertArrayHasKey($_ENV['CONVERTKIT_API_LANDING_PAGE_ID'], $result); + + // Legacy landing page should NOT be present. + $this->assertArrayNotHasKey($_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_ID'], $result); + + // Every returned page should have `embed_url` and no `url` key. + foreach ($result as $landing_page) { + $this->assertArrayNotHasKey('url', $landing_page); + $this->assertArrayHasKey('embed_url', $landing_page); + } + } + + /** + * Test that non_legacy_exist() returns true when v4 landing pages exist + * in the resources cache. + * + * @since 3.3.7 + */ + public function testNonLegacyExist() + { + $this->assertTrue($this->resource->non_legacy_exist()); + } + + /** + * Test that is_legacy() returns true for a legacy landing page ID. + * + * @since 3.3.7 + */ + public function testIsLegacyWithLegacyID() + { + $this->assertTrue($this->resource->is_legacy($_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_ID'])); + } + + /** + * Test that is_legacy() returns true when passed a URL string, matching + * how Plugin versions < 1.9.6 stored legacy landing pages. + * + * @since 3.3.7 + */ + public function testIsLegacyWithURLString() + { + $this->assertTrue($this->resource->is_legacy($_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_URL'])); + } + + /** + * Test that is_legacy() returns false for a v4 landing page ID. + * + * @since 3.3.7 + */ + public function testIsLegacyWithV4ID() + { + $this->assertFalse($this->resource->is_legacy($_ENV['CONVERTKIT_API_LANDING_PAGE_ID'])); + } + + /** + * Test that is_legacy() returns false for a landing page ID that doesn't + * resolve to any resource entry. + * + * @since 3.3.7 + */ + public function testIsLegacyWithInvalidID() + { + $this->assertFalse($this->resource->is_legacy(12345)); + } } diff --git a/views/backend/post/meta-box.php b/views/backend/post/meta-box.php index 35be6c9d7..1db6a84fe 100644 --- a/views/backend/post/meta-box.php +++ b/views/backend/post/meta-box.php @@ -69,15 +69,30 @@ landing_pages->get() as $landing_page ) { - if ( isset( $convertkit_landing_page['url'] ) ) { - ?> - - - - landing_pages->get_non_legacy() as $landing_page ) { + ?> + +