From 06a9d34770613eb42af288ca245f8708bde314c2 Mon Sep 17 00:00:00 2001 From: JordiPV Date: Thu, 9 Jul 2026 11:10:58 +0200 Subject: [PATCH 1/8] Remove AI Brand Insights Post Launch modal and associated tests; update introduction logic to prevent display on fresh sites. --- packages/js/src/introductions/initialize.js | 2 - .../ai-brand-insights-post-launch.php | 13 +- .../AI_Brand_Insights_Post_Launch_Test.php | 165 ------------------ 3 files changed, 12 insertions(+), 168 deletions(-) delete mode 100644 tests/Unit/Introductions/Application/AI_Brand_Insights_Post_Launch_Test.php diff --git a/packages/js/src/introductions/initialize.js b/packages/js/src/introductions/initialize.js index d5d421d8583..512648df777 100644 --- a/packages/js/src/introductions/initialize.js +++ b/packages/js/src/introductions/initialize.js @@ -8,7 +8,6 @@ import { get, isEmpty, find } from "lodash"; import { LINK_PARAMS_NAME, PLUGIN_URL_NAME, WISTIA_EMBED_PERMISSION_NAME } from "../shared-admin/store"; import { Introduction, IntroductionProvider } from "./components"; import { AiBrandInsightsFreeTrial } from "./components/modals/ai-brand-insights-free-trial"; -import { AiBrandInsightsPostLaunch } from "./components/modals/ai-brand-insights-post-launch"; import { BlackFridayAnnouncement } from "./components/modals/black-friday-announcement"; import { DelayedPremiumUpsell } from "./components/modals/delayed-premium-upsell"; import { SchemaAggregatorAnnouncement } from "./components/modals/schema-aggregator-announcement"; @@ -25,7 +24,6 @@ domReady( () => { const initialComponents = { "ai-brand-insights-free-trial": AiBrandInsightsFreeTrial, - "ai-brand-insights-post-launch": AiBrandInsightsPostLaunch, "black-friday-announcement": BlackFridayAnnouncement, "delayed-premium-upsell": DelayedPremiumUpsell, "schema-aggregator-announcement": SchemaAggregatorAnnouncement, diff --git a/src/introductions/application/ai-brand-insights-post-launch.php b/src/introductions/application/ai-brand-insights-post-launch.php index 667048c13e6..ed64135f5e1 100644 --- a/src/introductions/application/ai-brand-insights-post-launch.php +++ b/src/introductions/application/ai-brand-insights-post-launch.php @@ -32,6 +32,8 @@ class AI_Brand_Insights_Post_Launch implements Introduction_Interface { /** * Constructs the introduction. * + * @codeCoverageIgnore + * * @param Current_Page_Helper $current_page_helper The current page helper. * @param Product_Helper $product_helper The product helper. */ @@ -46,6 +48,8 @@ public function __construct( /** * Returns the ID. * + * @codeCoverageIgnore + * * @return string The ID. */ public function get_id() { @@ -55,6 +59,8 @@ public function get_id() { /** * Returns the requested pagination priority. Lower means earlier. * + * @codeCoverageIgnore + * * @return int The priority. */ public function get_priority() { @@ -64,9 +70,14 @@ public function get_priority() { /** * Returns whether this introduction should show. * + * Disabled: the "Discover Brand Insights now" modal is no longer shown after installation, because a fresh site + * has no search results or AI insights yet. + * + * @codeCoverageIgnore + * * @return bool Whether this introduction should show. */ public function should_show() { - return $this->current_page_helper->is_yoast_seo_page() && ! $this->product_helper->is_premium(); + return false; } } diff --git a/tests/Unit/Introductions/Application/AI_Brand_Insights_Post_Launch_Test.php b/tests/Unit/Introductions/Application/AI_Brand_Insights_Post_Launch_Test.php deleted file mode 100644 index 5be57f920fe..00000000000 --- a/tests/Unit/Introductions/Application/AI_Brand_Insights_Post_Launch_Test.php +++ /dev/null @@ -1,165 +0,0 @@ -current_page_helper = Mockery::mock( Current_Page_Helper::class ); - $this->product_helper = Mockery::mock( Product_Helper::class ); - - $this->instance = new AI_Brand_Insights_Post_Launch( - $this->current_page_helper, - $this->product_helper, - ); - } - - /** - * Tests if the needed attributes are set correctly. - * - * @covers ::__construct - * - * @return void - */ - public function test_constructor() { - $this->assertInstanceOf( - Current_Page_Helper::class, - $this->getPropertyValue( $this->instance, 'current_page_helper' ), - ); - $this->assertInstanceOf( - Product_Helper::class, - $this->getPropertyValue( $this->instance, 'product_helper' ), - ); - } - - /** - * Tests getting the ID. - * - * @covers ::get_id - * - * @return void - */ - public function test_get_name() { - $this->assertSame( 'ai-brand-insights-post-launch', $this->instance->get_id() ); - } - - /** - * Tests getting the priority. - * - * @covers ::get_priority - * - * @return void - */ - public function test_get_priority() { - $this->assertSame( 20, $this->instance->get_priority() ); - } - - /** - * Tests the conditional `should_show`. - * - * @covers ::should_show - * - * @dataProvider should_show_data - * - * @param bool $is_yoast_seo_page Whether on a Yoast SEO page. - * @param bool $is_premium Whether Premium is installed. - * @param int $is_premium_times How many times the `is_premium` method is expected to be called. - * @param bool $expected The expected result. - * - * @return void - */ - public function test_should_show( - $is_yoast_seo_page, - $is_premium, - $is_premium_times, - $expected - ) { - $this->current_page_helper->expects( 'is_yoast_seo_page' ) - ->once() - ->withNoArgs() - ->andReturn( $is_yoast_seo_page ); - $this->product_helper->expects( 'is_premium' ) - ->times( $is_premium_times ) - ->withNoArgs() - ->andReturn( $is_premium ); - - $this->assertSame( $expected, $this->instance->should_show() ); - } - - /** - * Provides the data for `test_should_show`. - * - * @return array> - */ - public static function should_show_data() { - return [ - 'on a Yoast admin page, with Premium disabled' => [ - 'is_yoast_seo_page' => true, - 'is_premium' => false, - 'is_premium_times' => 1, - 'expected' => true, - ], - 'on a Yoast admin page, with Premium enabled' => [ - 'is_yoast_seo_page' => true, - 'is_premium' => true, - 'is_premium_times' => 1, - 'expected' => false, - ], - 'not on a Yoast admin page, with Premium disabled' => [ - 'is_yoast_seo_page' => false, - 'is_premium' => false, - 'is_premium_times' => 0, - 'expected' => false, - ], - 'not on a Yoast admin page, with Premium enabled' => [ - 'is_yoast_seo_page' => false, - 'is_premium' => true, - 'is_premium_times' => 0, - 'expected' => false, - ], - ]; - } -} From 402d31c9e9ea6b2bbecdd170d6b88e84f92d6148 Mon Sep 17 00:00:00 2001 From: JordiPV Date: Thu, 9 Jul 2026 11:37:32 +0200 Subject: [PATCH 2/8] Remove AI Brand Insights free-trial modal after installation Disables the Premium "Your first brand analysis is free!" modal the same way as the post-launch modal, per the UX follow-up on the issue. Co-Authored-By: Claude Opus 4.8 --- packages/js/src/introductions/initialize.js | 2 - .../ai-brand-insights-free-trial.php | 13 +- .../AI_Brand_Insights_Free_Trial_Test.php | 165 ------------------ 3 files changed, 12 insertions(+), 168 deletions(-) delete mode 100644 tests/Unit/Introductions/Application/AI_Brand_Insights_Free_Trial_Test.php diff --git a/packages/js/src/introductions/initialize.js b/packages/js/src/introductions/initialize.js index 512648df777..658274be06d 100644 --- a/packages/js/src/introductions/initialize.js +++ b/packages/js/src/introductions/initialize.js @@ -7,7 +7,6 @@ import { Root } from "@yoast/ui-library"; import { get, isEmpty, find } from "lodash"; import { LINK_PARAMS_NAME, PLUGIN_URL_NAME, WISTIA_EMBED_PERMISSION_NAME } from "../shared-admin/store"; import { Introduction, IntroductionProvider } from "./components"; -import { AiBrandInsightsFreeTrial } from "./components/modals/ai-brand-insights-free-trial"; import { BlackFridayAnnouncement } from "./components/modals/black-friday-announcement"; import { DelayedPremiumUpsell } from "./components/modals/delayed-premium-upsell"; import { SchemaAggregatorAnnouncement } from "./components/modals/schema-aggregator-announcement"; @@ -23,7 +22,6 @@ domReady( () => { } const initialComponents = { - "ai-brand-insights-free-trial": AiBrandInsightsFreeTrial, "black-friday-announcement": BlackFridayAnnouncement, "delayed-premium-upsell": DelayedPremiumUpsell, "schema-aggregator-announcement": SchemaAggregatorAnnouncement, diff --git a/src/introductions/application/ai-brand-insights-free-trial.php b/src/introductions/application/ai-brand-insights-free-trial.php index c5a500bb6ff..dd6e5611201 100644 --- a/src/introductions/application/ai-brand-insights-free-trial.php +++ b/src/introductions/application/ai-brand-insights-free-trial.php @@ -32,6 +32,8 @@ class AI_Brand_Insights_Free_Trial implements Introduction_Interface { /** * Constructs the introduction. * + * @codeCoverageIgnore + * * @param Current_Page_Helper $current_page_helper The current page helper. * @param Product_Helper $product_helper The product helper. */ @@ -46,6 +48,8 @@ public function __construct( /** * Returns the ID. * + * @codeCoverageIgnore + * * @return string The ID. */ public function get_id() { @@ -55,6 +59,8 @@ public function get_id() { /** * Returns the requested pagination priority. Lower means earlier. * + * @codeCoverageIgnore + * * @return int The priority. */ public function get_priority() { @@ -64,9 +70,14 @@ public function get_priority() { /** * Returns whether this introduction should show. * + * Disabled: the "Your first brand analysis is free!" modal is no longer shown after installation, because a fresh + * site has no search results or AI insights yet. + * + * @codeCoverageIgnore + * * @return bool Whether this introduction should show. */ public function should_show() { - return $this->current_page_helper->is_yoast_seo_page() && $this->product_helper->is_premium(); + return false; } } diff --git a/tests/Unit/Introductions/Application/AI_Brand_Insights_Free_Trial_Test.php b/tests/Unit/Introductions/Application/AI_Brand_Insights_Free_Trial_Test.php deleted file mode 100644 index bbf3f3d7718..00000000000 --- a/tests/Unit/Introductions/Application/AI_Brand_Insights_Free_Trial_Test.php +++ /dev/null @@ -1,165 +0,0 @@ -current_page_helper = Mockery::mock( Current_Page_Helper::class ); - $this->product_helper = Mockery::mock( Product_Helper::class ); - - $this->instance = new AI_Brand_Insights_Free_Trial( - $this->current_page_helper, - $this->product_helper, - ); - } - - /** - * Tests if the needed attributes are set correctly. - * - * @covers ::__construct - * - * @return void - */ - public function test_constructor() { - $this->assertInstanceOf( - Current_Page_Helper::class, - $this->getPropertyValue( $this->instance, 'current_page_helper' ), - ); - $this->assertInstanceOf( - Product_Helper::class, - $this->getPropertyValue( $this->instance, 'product_helper' ), - ); - } - - /** - * Tests getting the ID. - * - * @covers ::get_id - * - * @return void - */ - public function test_get_name() { - $this->assertSame( 'ai-brand-insights-free-trial', $this->instance->get_id() ); - } - - /** - * Tests getting the priority. - * - * @covers ::get_priority - * - * @return void - */ - public function test_get_priority() { - $this->assertSame( 20, $this->instance->get_priority() ); - } - - /** - * Tests the conditional `should_show`. - * - * @covers ::should_show - * - * @dataProvider should_show_data - * - * @param bool $is_yoast_seo_page Whether on a Yoast SEO page. - * @param bool $is_premium Whether Premium is installed. - * @param int $is_premium_times How many times the `is_premium` method is expected to be called. - * @param bool $expected The expected result. - * - * @return void - */ - public function test_should_show( - $is_yoast_seo_page, - $is_premium, - $is_premium_times, - $expected - ) { - $this->current_page_helper->expects( 'is_yoast_seo_page' ) - ->once() - ->withNoArgs() - ->andReturn( $is_yoast_seo_page ); - $this->product_helper->expects( 'is_premium' ) - ->times( $is_premium_times ) - ->withNoArgs() - ->andReturn( $is_premium ); - - $this->assertSame( $expected, $this->instance->should_show() ); - } - - /** - * Provides the data for `test_should_show`. - * - * @return array> - */ - public static function should_show_data() { - return [ - 'on a Yoast admin page, with Premium enabled' => [ - 'is_yoast_seo_page' => true, - 'is_premium' => true, - 'is_premium_times' => 1, - 'expected' => true, - ], - 'on a Yoast admin page, with Premium disabled' => [ - 'is_yoast_seo_page' => true, - 'is_premium' => false, - 'is_premium_times' => 1, - 'expected' => false, - ], - 'not on a Yoast admin page, with Premium enabled' => [ - 'is_yoast_seo_page' => false, - 'is_premium' => true, - 'is_premium_times' => 0, - 'expected' => false, - ], - 'not on a Yoast admin page, with Premium disabled' => [ - 'is_yoast_seo_page' => false, - 'is_premium' => false, - 'is_premium_times' => 0, - 'expected' => false, - ], - ]; - } -} From 9273e210ffeeda3b226f5bf377e77be9177e1811 Mon Sep 17 00:00:00 2001 From: JordiPV Date: Thu, 9 Jul 2026 11:52:27 +0200 Subject: [PATCH 3/8] Remove the unused AI Brand Insights modal components MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Delete the now-unreferenced post-launch and free-trial modal component files (per PR review). The PHP introduction classes are kept (should_show() => false) so their ids stay registered in the collector and the introductions "seen" REST route keeps validating them — this avoids breaking any Premium version that interacts with the introductions system. Co-Authored-By: Claude Opus 4.8 --- .../modals/ai-brand-insights-free-trial.js | 113 ------------------ .../modals/ai-brand-insights-post-launch.js | 111 ----------------- 2 files changed, 224 deletions(-) delete mode 100644 packages/js/src/introductions/components/modals/ai-brand-insights-free-trial.js delete mode 100644 packages/js/src/introductions/components/modals/ai-brand-insights-post-launch.js diff --git a/packages/js/src/introductions/components/modals/ai-brand-insights-free-trial.js b/packages/js/src/introductions/components/modals/ai-brand-insights-free-trial.js deleted file mode 100644 index 1c84b155000..00000000000 --- a/packages/js/src/introductions/components/modals/ai-brand-insights-free-trial.js +++ /dev/null @@ -1,113 +0,0 @@ -import { useSelect } from "@wordpress/data"; -import { createInterpolateElement, useMemo } from "@wordpress/element"; -import { __ } from "@wordpress/i18n"; -import ExternalLinkIcon from "@heroicons/react/outline/ExternalLinkIcon"; -import { Button, Modal as UiModal, useSvgAria, useModalContext } from "@yoast/ui-library"; -import { STORE_NAME_INTRODUCTIONS } from "../../constants"; -import { Modal } from "../modal"; - -/** - * @param {Object} thumbnail The thumbnail: img props. - * @param {string} buttonLink The button link. - * @returns {JSX.Element} The element. - */ -const AiBrandInsightsFreeTrialContent = ( { - thumbnail, - buttonLink, -} ) => { - const { onClose, initialFocus } = useModalContext(); - const svgAriaProps = useSvgAria(); - - return ( - <> -
- { -
- - - { "Yoast AI Brand Insights" } - -
-
-
-
- - { - __( "Your first brand analysis is free!", "wordpress-seo" ) - } - -
-

- { createInterpolateElement( - __( - "As a Yoast customer, you can run your first brand analysis for free. See how your brand shows up in AI responses.", - "wordpress-seo" - ), - { - strong: , - } - ) } -

-
-
-
- -
- -
- - ); -}; - -/** - * @returns {JSX.Element} The element. - */ -export const AiBrandInsightsFreeTrial = () => { - const imageLink = useSelect( select => select( STORE_NAME_INTRODUCTIONS ).selectImageLink( "ai-brand-insights-pre-launch.jpg" ), [] ); - const buttonLink = useSelect( select => select( STORE_NAME_INTRODUCTIONS ) - .selectLink( "https://yoa.st/aibi-introduction-free-trial" ), [] ); - const thumbnail = useMemo( () => ( { - src: imageLink, - width: "432", - height: "243", - } ), [ imageLink ] ); - - return ( - - - - ); -}; diff --git a/packages/js/src/introductions/components/modals/ai-brand-insights-post-launch.js b/packages/js/src/introductions/components/modals/ai-brand-insights-post-launch.js deleted file mode 100644 index 70c99a3684b..00000000000 --- a/packages/js/src/introductions/components/modals/ai-brand-insights-post-launch.js +++ /dev/null @@ -1,111 +0,0 @@ -import { useSelect } from "@wordpress/data"; -import { useMemo } from "@wordpress/element"; -import { __, sprintf } from "@wordpress/i18n"; -import { Button, useModalContext } from "@yoast/ui-library"; -import { STORE_NAME_INTRODUCTIONS } from "../../constants"; -import { Modal } from "../modal"; - -/** - * @param {Object} thumbnail The thumbnail: img props. - * @param {string} buttonLink The button link. - * @param {string} buttonLabel The button label. - * @param {string} productName The product name. - * @param {string} description The description for the introduction - * @param {string} ctbId The click to buy to register for this upsell instance. - * @returns {JSX.Element} The element. - */ -const AiBrandInsightsPostLaunchContent = ( { - thumbnail, - buttonLink, - buttonLabel = __( "Discover Brand Insights now", "wordpress-seo" ), - productName = sprintf( - /* translators: %1$s expands to Yoast SEO AI+. */ - __( "New - Upgrade to %1$s", "wordpress-seo" ), - "Yoast SEO AI+" - ), -} ) => { - const { onClose, initialFocus } = useModalContext(); - - const description = __( "Track visibility, control perception, and stay ahead - tools to manage your AI presence are now live!", "wordpress-seo" ); - - return ( - <> -
- { -
- - - { productName } - -
-
-
-
-

- { - __( "How does your brand show up in AI responses?", "wordpress-seo" ) - } -

-
-

{ description }

-
-
-
- -
- -
- - ); -}; - -/** - * @returns {JSX.Element} The element. - */ -export const AiBrandInsightsPostLaunch = () => { - const imageLink = useSelect( select => select( STORE_NAME_INTRODUCTIONS ).selectImageLink( "ai-brand-insights-pre-launch.jpg" ), [] ); - const joinWishlistLink = useSelect( select => select( STORE_NAME_INTRODUCTIONS ) - .selectLink( "https://yoa.st/ai-brand-insights-introduction-post-launch/" ), [] ); - const thumbnail = useMemo( () => ( { - src: imageLink, - width: "432", - height: "243", - } ), [ imageLink ] ); - - return ( - - - - ); -}; From b8b20713850042436f67218bc96fb3d60f2c18eb Mon Sep 17 00:00:00 2001 From: JordiPV Date: Thu, 9 Jul 2026 11:58:49 +0200 Subject: [PATCH 4/8] Remove the unused AI Brand Insights pre-launch modal component Delete the already-disabled pre-launch modal component too, so no dead disabled-modal component files remain. Its PHP introduction class is kept (should_show() => false), matching the post-launch and free-trial handling. Co-Authored-By: Claude Opus 4.8 --- .../modals/ai-brand-insights-pre-launch.js | 110 ------------------ 1 file changed, 110 deletions(-) delete mode 100644 packages/js/src/introductions/components/modals/ai-brand-insights-pre-launch.js diff --git a/packages/js/src/introductions/components/modals/ai-brand-insights-pre-launch.js b/packages/js/src/introductions/components/modals/ai-brand-insights-pre-launch.js deleted file mode 100644 index 934dbfcc998..00000000000 --- a/packages/js/src/introductions/components/modals/ai-brand-insights-pre-launch.js +++ /dev/null @@ -1,110 +0,0 @@ -import { useSelect } from "@wordpress/data"; -import { useMemo } from "@wordpress/element"; -import { __, sprintf } from "@wordpress/i18n"; -import { Button, useModalContext } from "@yoast/ui-library"; -import { STORE_NAME_INTRODUCTIONS } from "../../constants"; -import { Modal } from "../modal"; - -/** - * @param {Object} thumbnail The thumbnail: img props. - * @param {string} buttonLink The button link. - * @param {string} buttonLabel The button label. - * @param {string} productName The product name. - * @param {string} description The description for the introduction - * @param {string} ctbId The click to buy to register for this upsell instance. - * @returns {JSX.Element} The element. - */ -const AiBrandInsightsPreLaunchContent = ( { - thumbnail, - buttonLink, - buttonLabel = __( "Join the waitlist", "wordpress-seo" ), - productName = sprintf( - /* translators: %1$s expands to Yoast AI brand insights. */ - __( "Introducing %1$s", "wordpress-seo" ), - "Yoast AI brand insights" - ), - description = __( "Track visibility, control perception, and stay ahead - tools to manage your AI presence are coming soon!", "wordpress-seo" ), -} ) => { - const { onClose, initialFocus } = useModalContext(); - - return ( - <> -
- { -
- - - { productName } - -
-
-
-
-

- { - __( "How does your brand show up in AI responses?", "wordpress-seo" ) - } -

-
-

{ description }

-
-
-
- -
- -
- - ); -}; - -/** - * @returns {JSX.Element} The element. - */ -export const AiBrandInsightsPreLaunch = () => { - const imageLink = useSelect( select => select( STORE_NAME_INTRODUCTIONS ).selectImageLink( "ai-brand-insights-pre-launch.jpg" ), [] ); - const joinWishlistLink = useSelect( select => select( STORE_NAME_INTRODUCTIONS ).selectLink( "https://yoa.st/ai-brand-insights-introduction-pre-launch/" ), [] ); - - const thumbnail = useMemo( () => ( { - src: imageLink, - width: "432", - height: "243", - } ), [ imageLink ] ); - - return ( - - - - ); -}; From 257c623e0fa09948af59166c527698eeca1bc36a Mon Sep 17 00:00:00 2001 From: JordiPV Date: Thu, 23 Jul 2026 09:58:40 +0200 Subject: [PATCH 5/8] Remove unused image file: ai-brand-insights-pre-launch.jpg --- images/ai-brand-insights-pre-launch.jpg | Bin 14370 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 images/ai-brand-insights-pre-launch.jpg diff --git a/images/ai-brand-insights-pre-launch.jpg b/images/ai-brand-insights-pre-launch.jpg deleted file mode 100644 index 30f470ad510713f1f7aadbc809a17a26ff11c431..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14370 zcmdsd2UHZSFj}8n`JhBPRo3VF3UZ zxC0ksz^j`8!EZYucqIgGf;%B_8z2R4fyZrt2A~2cz?}*#aRB!Ky59~CKnh?5xWVJc zSqcyVs|02A==1>is+xWj=upbR{YfFmsB%aB`e9Sabk3G1e7gtc$PUoUs7xE0^s0eZ#`Of^+REE?6mi6TrsCx`K^^gL4)8 z8uk_Nk;}@f#3c70+@gD^dhIs18qcF=PIu@TQX77WB z-x`B8%*0>~fDK%|f^+4!fx&JsJAJ5ni~A+cGpAI#hF+eFQQ!txk4=1q7!U`J9sgrb z|DTnwPq^vykGPenzNW)Ky&06C!&N#qtVrmS>BWv+S%EFham&Vr?~4MlUW?b~+U?)F zMdqZNHE0%2vle8DK%%8M0EgEwT63gdbsRbulFcOX-yJt7ikgog zA`%zpupHHIO>|C$TX!OS4Ib2gZ56(uxaKq9lBRU1)n2tbW+l}WA0P3HRAHUZQ-spm zT zrO#hp)=+5jrD#XM9=N{?J6}(ZSj@ZYkk|6$*i;)6aTyOgH^9w(?O+ z%rN=Qh6|wE&YFMGQb#BOsS$hfC>w8rQP^sckw%d)<8JX$7n??3u3nt7BKJ|FQ=P$a zqe#rGC;8E6zBrLT$@%?gyMwMLF$im_;W?CqFL1Xx>{LEX3zd0eGd4-h`KYbYMIGiq z>N+FwH>Fl<6C8qau0SF=9$f%Yxz@y6<1uEmQVg=C1mr8Rk49QvSvkwY@}49Yi4!W5 zcPTtCqws2$%yplV?K~n|-bUviA|vdSW{)r3wy*GRC8@ljFbt9H_D)lr zOKIfO?Z1uoFI}++RbLxq?917Ye36~=V()q*s-qqQaljj?N|~)$HQ(9|wPGHNIo;m> zrE68^@VQ?3D;bfQ8BIL53E#D1`ju(vW+%1KXhq`R=lBn!;{FoGzGNX-;bZOAwAm{i z8pd-A!eTmtJDba>ynHTqAOU=B$|j=B^D-%OYm#AB&zw$Hv;H850}6uK;+Pre z!*!BP+0XgUWcV1j^HEXj)LoyimGV;a6Q{B!517`xbz3*NzwD|W3r`7BIEruBsH$vs z=6^v0`*N%_%q7gmbf<-$^8osY`a{^dieh8G2*igWKWEcm27>>^-#qj)0VLJRMkS7_ z`CKErCocseUR&?X+{@c3RBWwLRXsQ)Y`U;euhlh;8y}RqTuF9V`pDk;EdqOV`l1aP0h$#GX zJh0CG74&ZD*0Q5ovPLS3&oy5`_sh^=$j5m}NaEcYYbomI0P~*?c12dKvO8=XD%j59 zj}kecU2MNg+bMh`qwfbB-@g@uK`mcB>nvX8t$(y1L5t0TF=3Xpxwkkc8ey6qgM{-| z7=1)pW%L3d#`u>v7Pk8oGK6yShVUwvuY+`x?tGu*x)B`Zw9Cv)bfVd2PBF&wF`0cV z2d0S~brgtjLJfvYyvdcqgJ}#s6OEQ{T(4Kmez}q|cZ|kuScb2M^pdMIdpRPNWrUBs zU~SQ=g6$2BVsR!!Bvw5_sj}R7$D}t;_oszLs-b?g!lxxSiSPE+bZR|SX6@NwTnwaR zVh_|Nr5#FGN4E=gd611Q0g<8Zn@t@bmt29x9cS)=WQM|G-o{vt6{ks}NhgcC%yyPd zv@t$#_0MMPbODf>Jk|S@>F3aHno}X&&5;g2jHVUFIL#&Hw6HO`gg#iwv7;TdJ&rSv z4aqSCS&29=C+kaC1~Jw}avXG2g^vZ0{^hqaNOEb%2dziD|U#?`Z6cZzI?)o(!X~BkcfXG+9F#6P6Ue9yUNSS|xlq1=daN_xNLtYG^2&)?uLsaG8CuT^MzpM7;}g_kLu zL=R)@13+ffjKO@|x^!&>C1nNzF?uU*OVw$;=55y??;dofx}w}jn;d?09kWopILk+! zs3zycN3TuUqpe#~ks9W@rXCO}?-B|dr+av;G47o2J$mFay#KK^o9^S7Mt>@2 z7fIusXS9}4{Ojm!PiY4t&Gq9Cc&!L4UYxXLd&gB;o!9>sga2}R|3$@Baq1Io+6}{s zcl(B{hEwB0jKz2iQ6m7As>(-=yY7Vr`gZmAvo_hx`qX7ORCHSVxz1@b_jZ%Ai!zsa ztzzv6GHvUs3FIJ2UOS=R+v?;d3&&E98#0y#ta=xjvLiWnE&yWDxSG}~t(sQ-vABc$ z)h6V^7e7%bpEB}8CccN_+*SC*a{?^AyGFH%q{$hx?SFQs+LlD$D@50n z^>sFsxrsABk>5TuzF=O2L;QK~(K?IUQ9X&Nkd<2^}7I&EC1natRNyBUj>OaQNm#HOx zHwv0A2c9AEy`4P*1uEs#G1q#_<4;vx1JOLF9ynZvnj5wJu^B>i=J2(Os&=K} zb%<(M!WO|QgzLGn>{4LW=zykcM7S~Y0f5nk5;_> z?6w61g=c>Gm^J=YHRqKf2}Y>*IQ1Gz`vNGk|14|#aMp%$ zK*-K73Z>A7-DacHT#=L5y~>G1nk>g`r|8zF(Jb=3%9>xP$U9TWqn+t9MZ1P!04|G=w=w8N7RV zRd0u$-il+gjRw}E%SDl^HtG}x%Y~aa>h1m#K{Dyb%N4Ap&5;mcZf?nTONqaa(ROgD zN(QkKj6`djMV-!^o- zf}OKV*@c7c3Xapw)YU?(c@>15F|$Lon+eMwFTD}os#FzM=9%g~BX6H&xWqqac@L6q zjUBO-H{*(oDlqB;h{9|}rFd)B`DxhK%X>u2RR#^hF95x7nK_dit*r@7S#Ji2_YlyC zunS-orG19mw@rUWs=oK#;sSW3JwhLRNOXS7|E#}zeAe&E1@L<60&t-(XWRp@{v{~9 zruJZKs?4VPfCL`FWeq>z8pa!b=j_#uT1{zt%IV3yjNXn@9-EsRVnTJ8=nbU?oQAsQ zwZSbBLRvxMWQ%Us*4p4Y4f{bQ8J3Zaeqypa+=~-+xe%GSrp-d;%>u=(g{>_={UegG z19p7+P7=K1fHpo)aQr!gW{D3(Mn9eP{|iANan%%>)SzXu!{Hm{7=<^nE81A$SQCvS-XHPeM_o76W8HfiBPi~ePIrK69O?sCioZ)zFoCe_Twd`LN zu{NuXEa!Z%arKK_Dt>co&La>`FwK?1PG0m`$|!S%z5oDuPOcdLfjbkt2zIITrcK&C z2@Mj2jjMzvrIKxX)`{4{qcEm&GmX20`Kjzdr-M}Ai?v~9^cfSIB^x-kLMC3#)m<)L zDqjh@o~^J9`FPoPrxwsy?nUH^*r~`h_oprz*uj+EelOxvoFK&n=0I5e8M9FE-XVkM z3vdIMeDAq);S97~nv&ky>vSrss90zHUGsLU{NBLmz7e(mivOOYVHL8N3=o6dEAL0$1#Ef=wFH9Wz+ za|#kE;8M>97s@m+A>RtdtkAz=o=}RcUQTa_8mp1#ATU}U%}pYHolW65YE?U1>lhsA*EP&-cH|86h%rwdUf!HuO}^@bFkKo3Aun&D z`{9&d=W3@|&-K5~%x)fUO*z=LY`3bu*iD+`OY z%YIb&_K)$>KQizdRBrMNX;`n;mlD1Y3%qnLLAEdN-zjd@#8-A!4b@sNp^=f+8IT_{ zPsc0BPvjd~IF)<1obB~Jl}jW9Vt;BN;OD*u9SHD!}$EFz6>w*?*YK%XX#*?tKl}!D{F_AT)sJ$lj?ow_iSjd;UlSInuq{=|Q5pZ}Kk+GlHh_Tmu( z<QTH9|9rrVPINZrNESWm5Tq|Y4p6x*1aRb$NVFqf4mc|dQ}vau;vEiBt@Z3=~X zS}oNPdJdv`Amw%b@aLdolIvL(>K60ysZ&tf88}zn%t9zplw`wo2Kiia1|9>K3-Q0V zu}GIk1Hj)fBUa#+|I!7}=6NY**m%8Exx_J5wsF53yPZ&=UEf*yO1C)G zEiR*4a|?$XI`xcx3mG1>GYGhMt+Bs!>WC$tR!z(ds87=4elTX;2uVvy(ikDKlvG3)oMG!5nw|6 zC?qcdR=mJf2wC$Fan9YtA(0>-wJLwJoZst01;P*3j2xD%3aP8A8H1g<4!-fuAZmP; zar07s+R&UO>!Z`b8?jK;RdiaUF9fzI9@7&M5LJ83LbHXj_R`|dBodFBuPIMgJHQw& z?9?1WeHP1W=h7LbKb6@|(Ch`~Fs+=HCk<#l8fIyfSM^2kSSa7E5t^%q)*%eAW(PCB zATVpP_kd9e07HGa+5c|~ktP&?j%HJ4jq{gV^EgF0#GRvM^tPQXaAG^U1oMyiD@2>{ znC8=>eMhg~jIhkGsf-{VaR^dR>e}*EY(;Xox0fdY{#y+uYSq~34A zJ0@n1f+KC{1)C?btoW*SHHNxVwFj*R6OKckIKTHaV7A?K|R%*^eE`8s!9ik=f!c z_^2+_H-ii>-L4HnlhnuUz*YJtTAy3pd+iI0GVGZtW*_@2u33Wky;q2cxS#gCqbS|V zhn}`|`#)V2|HOot0J5QH0cOx{Uz4$7cE;P^2whHap=U3-r_wh7my}`6c59pGUZj^A z2!IVh3IINF!>&!ijXFL`ZCFOw&A0LH;yy?Ou7kBwnNW{k=(lK3KjH;Mt1eTY#T%)e zD7?E$1s|1kK2eBqa2U^R9*>FZT{-zMUf0)VSC8}^zMk%UB45E(T7{JbwMS1fsz=LJ z#vP-|(7hy=4K=HLGg}GxxQlW-voxmEV#I4;OU_lOaOFT(M@K|}Ym;2nK|b7}+-;z2MkL|X=DD)3iSfv>;J)|miUl>*kk}}- z0w>HyFQ`v%T5HoA-N!gZAmY4F6Dt|Hkmd?WZH`HU%rY(pGO23f!d=l=`1J;s5=Ez>h_U#hk-|pd%RI z`$^OnP8xgK(&H+C#2VPDZ8PoHMI>B}q$KoLgBjCGcxjGqjf0@z(+ti!CF^Ym*A?ah%H&m~|N(TF1fh zbr@xS2i%mC6Rp?6kz4QexX)3s3a%a&hU*_$JfVYl|&e1iz?SR&ZW~JS=yqvI$!R-W#2A7# z`tzoq+u0LIKjTzXBzO-o6_kNE`QNs9|Ipx4Fj6vVx$>lLC#H{MG@=y=3_9gqER)D& zpFf^;;^z9sV??U&K#qq^pdl8*I&+jTq@C*|D?g*n&&7R~rLdd-V>K9lt!8+uyV(3P8>%7aBS z6*^znT@zP!KIIleAJoaSC_9}5N}_SQ%ckDC#S~k-Qu!q;!sc~Bif8MF>uO%TazlBW z19WZ(a?;N7OC^C1GEjEJm0|2i1Kj^|AZtDg-ccpg5;5PxB0EDWLV2;~J=2dvR6ner>cZE0r97yYFSbMJzwTP?VS>R;E2l zgV_ZEs)GC9R;F@EUX5XqleS3J?()ztDU#m?Nj#xqJ~;<|P0@uyyC%?Pzih}{O7vyL zZ%fuB6Nua2+4Pzp82kv(|ACvo6R|{B%`UQPN#m|Rny1@(yKH7hsQ)yJCEwf&ITUlHV^N6ODfzPyo} z`?Jb!@Nn`M9=Y_`K}XA+AzQQCNkyYX6T1`Cx?QH0M-@|c73{ig^-LQ^8lD$`dIT-4 zI`xn})nGMhMKsaCQjtIz{2HQNhL z_D4M>u;sxw2)pzyG#{%QyP2CW14@~u$RbOD-Eq*~4GaO~!H}1c(yBa!388dNn}A7^ z`zvW^xsT~}Fh+TofgX8n0AOVk7Ok&IM!AIS4o5NSZQWL1uFxPB5552}62OP62IXh^ z0H#8EoBpLpHhvz>B~QZQ33&L{^p&8xe3E2HS=p-bgD z!XGSyhmvo9A{X0JJl1rDl7`aBduV>uwAf4ADj#i@>Gnjw-RUtv zC!jX}Aul9aKeJxzB`R57jKNc^!;t~k&I$1fq2?P&(r*dlF{Dx+HQBw#K&<6Gxuac6C zwKDkF!#j(Q#^sCe4J6^%Yj(5s|Agp+Gbv`xKgoYw!&q`g@ajp8`H;*{RDevY_!Ak4-A*`;3-lh)-Oa#K@#9k(2h=H3}G zEAGzI1yM&-81I;Lw37Wx_RCBx)+P980>MWs81G)WPqi+1-uW{B=p6;#J!ITe6;731 zv0i`8)eo51-gf6;+$(+NLbw0mZBg*d5O9=79XYnlQ z(YE`mM=!Re>|gq<-xVhMQLmViNMgz*nlQ=w7fsWgb}WIAXUu%#SB%g4>ll4?HPLst z;*pGVv-1naa;mJ1rFT7*K%ie%Ie_ve^&P-x%q6v>Xk;BW1hpx{Nrw{wGYBCgM-Q;&@uP=_0h*5|f{bs;Sx zYZ!7coMMTlwlF-I3FGS#B1_5~vMbwb-Jygn;?wOE>$#QPoeZf0w4I^kp9<8`GcqEn zzOV=gHHxvcKc!%8`SY5m5Wfg(H;qm|j`i?$vq`+Jlr2~4x)oC&)r?eikl;H}vLk(DqS(_Z|2-TBGzGuXZ zt3}MjJ8j*!y#SKJGt1+pd^(0YT|c-(bCIe?(0OC!;pcZrW;3P__GEL?ob(LTB4`&B zQp^09IHio&LaXxoVoYcI{ENJD1NfRzv*~#GQIC4x0n-0b!Jp+E$e8F6S<#zvfEnvV zsMq@>XIRcB?Dqa^Uq56#waP-XsqMdrHq985qaqHLsK{b82>ldDtM)lmfB5%)urCoE zpM6#}GM21K{+7NQe`}0JT+b(na|hev_t*=7z(Ody=DWRx1Aenp=nNxs8-xNf-Vh(C zY(~=Ds^6%P5w38B^Ni@h@=>9Wr{C?aGxUMCNWE(E;(7dD3g8b2ci2I9tyO+yMuFMy!hsUsTH>dS#Z>oRMGj$fN<{Sh~K`W~ghWzlYy13v#4VFTRd`cc9{m&pjQ3*3XiYMR|kywo41+XZn!f z=pETrnG-C#vmgG34n#KVOCeYc*w`71d`VVwd_lhk87i$Ht`RXTdH~{@6F*7*z|=g( zoxj7H%}|R7arNk}o_1bQqWKFTr_E>E;w(H7TYs#lb~RdC?*kC}r`#kY+I$MkaMgyB zoD2hk3Y#Xc>-GUc@CKy4xB}jQwEvX{aKP8?2k!Kmj;@(%6{_Rmo94$d*L4b(o1j0hxhO&d(iPQLv_f`_H%a@<_9onT@DE{I;n zqsN1MDKS5C4;Aw~OJ20?4zV#{q%s74+PDl=1Uu*FPhGYxy=dDuV`CRPQryo7--D9t z`c-lO&eK0k^WP(2eZ;bC@i@NId!5rTG`P^+Opfkxi*W(lH}J>yKijYfn8NAx&<>wl z&mpgRvukEOuIi~>27t9fPR>T69-^X)9beI9*WK>Ax%r-efXsZWWrf_6lF+#OYxv>L zvLLk#zb1vNBwf4%zJCp@gu`RL*+Rc1neWW6>t#NKp^bGap193X0$b&Z&L9obZ{G3f zT4A0~*6?u0kMNHFQjrhZK|KZ|H%bt>uO}}4Q1Q0ZB^#pSM0gLY@7S);(;H*IG3u{W z{LiNNmoz?tkJ1b_4Gs*pvH1WtH~3XKO2xRjGpVh za3BQPtXmIlpk-ttY{}h_Z;BLx{g_@M``{Rca?9ds$L&K7MADp5QKn(pm;w9c-wc!7 zQWXob_cgY~s5_5r#**(uba0vEsi`@}=vgbc4r!p-3L&(CNG{L1*mvK{d`&R?&COsA zVr-ijxw1)SYhc#H=_}+XX#>VHw0lslWQ~)GC59CbZRl_C6AX0D)qU~`#Wc=fKMZZf zrJ4uKSS>0TanJ!5}irZt+QoLocJL+X;=9Dg5775BF zIWpbc_T=Q>LJ})EckUhY@yojoK?i3bx5sHy>6QAo_!M>KXS*u-ztO$;0~3DkuP%9T zGlG1N;WnV)ivnz$pvUxgtNe^JttDz8MG~aVqft)>WS%>Zb;{T-JN~(r#Q70W9HP?( zrb=to1wXFxS;d`(X+V1w6B$i27tdyW@wPU;m5yznTf1(WpCIDAYwwCwc2>=AERL$g z6-1|^1MK3t6Uy6a=b#>{7E+|2fT- zdRI$hk}{=_d-3ww`L_o)lt$??nb|AP$^C@VNM5D8-9qAM3w&>mkIbIY-(d@@Fl1vS zT!B3P18;v2uH2q3x1*4teDhe+FE1~y&vH0;fIfFHF7AMC#o7o!CbsYIN8aaqiQhv%GrvAh_b*3+5#_{SHWcxKV|iaiJIEp zIDzYswje`2**+Zk1=$L{LKip|D?dQkd9ZsP`wEzhiPMGhFC|QDc!A#Q$)CLTA4nN% z0XCjp(tdeWvnwm&53-$8$7|${NH*twdbDeL7{gZ-8>PU zw^QIzd)d((P{+PHJtrCkrvU%^-;J<#e^f>WWzOo;KQ4!uvW3LVr{9?yd6inr$awxEv2bO~=V^{=Qkc17LYga|h0shR1V0!yQlOW_qnLhwWzSxgzkXX$7^I=gv3twP1O{47v%6jyAIeeJyo zb9bw}&bunqZ015_d0~ICAz$?=zR>OLCZ_&C$pKv6Y(E+0NYetRXsvD4wQ=3PcL0{e zAGnW;SN{GF#QzQf>sD6Ihz901M%|ukq^#&3UNvc6@PvDlJlD6+yETtZ+Or9xz3U3y z&&K!xN~B8jOVyeBBo(CHwp7hsd+mm_0h)w2b5cIy4GD?--n@U0SpGYl`hTYl I(Z$IB0qCK1lK=n! From cdc9e6b21bc9ad78381a14b57a9d64e5f7b25d24 Mon Sep 17 00:00:00 2001 From: JordiPV Date: Thu, 23 Jul 2026 10:19:15 +0200 Subject: [PATCH 6/8] Update messages --- src/introductions/application/ai-brand-insights-free-trial.php | 3 +-- .../application/ai-brand-insights-post-launch.php | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/introductions/application/ai-brand-insights-free-trial.php b/src/introductions/application/ai-brand-insights-free-trial.php index dd6e5611201..335c97e215a 100644 --- a/src/introductions/application/ai-brand-insights-free-trial.php +++ b/src/introductions/application/ai-brand-insights-free-trial.php @@ -70,8 +70,7 @@ public function get_priority() { /** * Returns whether this introduction should show. * - * Disabled: the "Your first brand analysis is free!" modal is no longer shown after installation, because a fresh - * site has no search results or AI insights yet. + * Disabled: the AIBI modal is no longer shown after installation. * * @codeCoverageIgnore * diff --git a/src/introductions/application/ai-brand-insights-post-launch.php b/src/introductions/application/ai-brand-insights-post-launch.php index ed64135f5e1..e627aaefa01 100644 --- a/src/introductions/application/ai-brand-insights-post-launch.php +++ b/src/introductions/application/ai-brand-insights-post-launch.php @@ -70,8 +70,7 @@ public function get_priority() { /** * Returns whether this introduction should show. * - * Disabled: the "Discover Brand Insights now" modal is no longer shown after installation, because a fresh site - * has no search results or AI insights yet. + * Disabled: the AIBI modal is no longer shown after installation. * * @codeCoverageIgnore * From f5cb7cd1db8f257cbe589959cf077511183f47c5 Mon Sep 17 00:00:00 2001 From: JordiPV Date: Thu, 23 Jul 2026 10:55:34 +0200 Subject: [PATCH 7/8] Update comment for clarity --- src/introductions/application/ai-brand-insights-free-trial.php | 2 +- src/introductions/application/ai-brand-insights-post-launch.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/introductions/application/ai-brand-insights-free-trial.php b/src/introductions/application/ai-brand-insights-free-trial.php index 335c97e215a..80f091aa867 100644 --- a/src/introductions/application/ai-brand-insights-free-trial.php +++ b/src/introductions/application/ai-brand-insights-free-trial.php @@ -70,7 +70,7 @@ public function get_priority() { /** * Returns whether this introduction should show. * - * Disabled: the AIBI modal is no longer shown after installation. + * Disabled: the AIBI modal is no longer shown. * * @codeCoverageIgnore * diff --git a/src/introductions/application/ai-brand-insights-post-launch.php b/src/introductions/application/ai-brand-insights-post-launch.php index e627aaefa01..871d2c97232 100644 --- a/src/introductions/application/ai-brand-insights-post-launch.php +++ b/src/introductions/application/ai-brand-insights-post-launch.php @@ -70,7 +70,7 @@ public function get_priority() { /** * Returns whether this introduction should show. * - * Disabled: the AIBI modal is no longer shown after installation. + * Disabled: the AIBI modal is no longer shown. * * @codeCoverageIgnore * From 7b0c53032342a742423f37ab2df5092976f97735 Mon Sep 17 00:00:00 2001 From: JordiPV Date: Fri, 24 Jul 2026 16:11:08 +0200 Subject: [PATCH 8/8] refactor: remove disabled AI Brand Insights introduction classes Their should_show() already returns false and the JS modal components were already removed. Verified against Premium's trunk, 28.1/28.2-RC1, and the shipped 27.6/27.9 release zips that nothing references these ids or class names, so keeping them around is unnecessary. Co-Authored-By: Claude Sonnet 5 --- .../ai-brand-insights-free-trial.php | 82 ------------------- .../ai-brand-insights-post-launch.php | 82 ------------------- 2 files changed, 164 deletions(-) delete mode 100644 src/introductions/application/ai-brand-insights-free-trial.php delete mode 100644 src/introductions/application/ai-brand-insights-post-launch.php diff --git a/src/introductions/application/ai-brand-insights-free-trial.php b/src/introductions/application/ai-brand-insights-free-trial.php deleted file mode 100644 index 80f091aa867..00000000000 --- a/src/introductions/application/ai-brand-insights-free-trial.php +++ /dev/null @@ -1,82 +0,0 @@ -current_page_helper = $current_page_helper; - $this->product_helper = $product_helper; - } - - /** - * Returns the ID. - * - * @codeCoverageIgnore - * - * @return string The ID. - */ - public function get_id() { - return self::ID; - } - - /** - * Returns the requested pagination priority. Lower means earlier. - * - * @codeCoverageIgnore - * - * @return int The priority. - */ - public function get_priority() { - return 20; - } - - /** - * Returns whether this introduction should show. - * - * Disabled: the AIBI modal is no longer shown. - * - * @codeCoverageIgnore - * - * @return bool Whether this introduction should show. - */ - public function should_show() { - return false; - } -} diff --git a/src/introductions/application/ai-brand-insights-post-launch.php b/src/introductions/application/ai-brand-insights-post-launch.php deleted file mode 100644 index 871d2c97232..00000000000 --- a/src/introductions/application/ai-brand-insights-post-launch.php +++ /dev/null @@ -1,82 +0,0 @@ -current_page_helper = $current_page_helper; - $this->product_helper = $product_helper; - } - - /** - * Returns the ID. - * - * @codeCoverageIgnore - * - * @return string The ID. - */ - public function get_id() { - return self::ID; - } - - /** - * Returns the requested pagination priority. Lower means earlier. - * - * @codeCoverageIgnore - * - * @return int The priority. - */ - public function get_priority() { - return 20; - } - - /** - * Returns whether this introduction should show. - * - * Disabled: the AIBI modal is no longer shown. - * - * @codeCoverageIgnore - * - * @return bool Whether this introduction should show. - */ - public function should_show() { - return false; - } -}