diff --git a/classes/Visualizer/Module/Admin.php b/classes/Visualizer/Module/Admin.php index e7ef36e5..0074a3b0 100644 --- a/classes/Visualizer/Module/Admin.php +++ b/classes/Visualizer/Module/Admin.php @@ -1119,6 +1119,8 @@ public function enqueueSettingsScripts( string $hook_suffix ): void { } wp_enqueue_style( 'wp-color-picker' ); wp_enqueue_script( 'wp-color-picker' ); + + do_action( 'themeisle_internal_page', VISUALIZER_DIRNAME, 'settings' ); } /** diff --git a/index.php b/index.php index b5f21108..9e49ac8a 100644 --- a/index.php +++ b/index.php @@ -189,6 +189,7 @@ function () { ); } ); + add_filter( 'visualizer_support_hub_metadata', 'visualizer_support_hub_metadata' ); add_filter( 'visualizer_ai_connect_metadata', function () { @@ -274,6 +275,38 @@ function visualizer_action_scheduler_store_class( $class_name ) { return 'ActionScheduler_DBStore' === $class_name ? 'Visualizer_ActionScheduler_Store' : $class_name; } +/** + * Opts into the SDK Support Hub: one Help button on the plugin's own screens + * and the deactivation window. + * + * Visualizer Pro registers nothing here: it has no admin screens of its own + * and the SDK shows one Help button per screen, so the free plugin owns the + * hub for both and tags the message as pro from the Pro license status. + * + * The plugin screens need no `pages` entry: each one fires + * `themeisle_internal_page`, which the SDK already treats as a product screen. + * + * @return array{is_pro: bool, license_namespace: string, links: array} + */ +function visualizer_support_hub_metadata() { + return array( + 'is_pro' => Visualizer_Module::is_pro(), + 'license_namespace' => 'visualizer', + 'links' => array( + array( + 'icon' => 'book-alt', + 'text' => __( 'Docs', 'visualizer' ), + 'url' => VISUALIZER_MAIN_DOC, + ), + array( + 'icon' => 'groups', + 'text' => __( 'Forum', 'visualizer' ), + 'url' => 'https://wordpress.org/support/plugin/visualizer/', + ), + ), + ); +} + /** * Registers with the SDK * diff --git a/tests/test-support-hub.php b/tests/test-support-hub.php new file mode 100644 index 00000000..312ca80e --- /dev/null +++ b/tests/test-support-hub.php @@ -0,0 +1,84 @@ +assertNotFalse( has_filter( 'visualizer_support_hub_metadata', 'visualizer_support_hub_metadata' ) ); + + $data = apply_filters( 'visualizer_support_hub_metadata', array() ); + + $this->assertIsArray( $data ); + $this->assertArrayHasKey( 'is_pro', $data ); + $this->assertIsBool( $data['is_pro'] ); + $this->assertArrayNotHasKey( 'setup_complete', $data, 'The setup nudge stays off for now.' ); + $this->assertArrayNotHasKey( 'pages', $data, 'Screens are declared through themeisle_internal_page, not pages.' ); + $this->assertArrayNotHasKey( 'primary_color', $data, 'The hub keeps the shared SDK accent.' ); + } + + /** + * Every footer link has an icon, a text and a URL. + */ + public function test_links_are_complete() { + $data = apply_filters( 'visualizer_support_hub_metadata', array() ); + + $this->assertNotEmpty( $data['links'] ); + $this->assertLessThanOrEqual( 6, count( $data['links'] ) ); + foreach ( $data['links'] as $link ) { + $this->assertNotEmpty( $link['icon'] ); + $this->assertNotEmpty( $link['text'] ); + $this->assertNotFalse( filter_var( $link['url'], FILTER_VALIDATE_URL ) ); + } + $this->assertSame( VISUALIZER_MAIN_DOC, $data['links'][0]['url'] ); + } + + /** + * `is_pro` follows the `visualizer_is_pro` filter Pro answers from its license. + */ + public function test_is_pro_follows_the_license_filter() { + $this->assertFalse( apply_filters( 'visualizer_support_hub_metadata', array() )['is_pro'] ); + + add_filter( 'visualizer_is_pro', '__return_true' ); + $this->assertTrue( apply_filters( 'visualizer_support_hub_metadata', array() )['is_pro'] ); + remove_filter( 'visualizer_is_pro', '__return_true' ); + } + + /** + * The Settings screen declares itself a product screen like the Library and Support screens. + */ + public function test_settings_screen_fires_internal_page() { + wp_set_current_user( 1 ); + set_current_screen( 'dashboard' ); + + $admin = Visualizer_Plugin::instance()->getModule( Visualizer_Module_Admin::NAME ); + $admin->registerAdminMenu(); + + $fired = array(); + add_action( + 'themeisle_internal_page', + function ( $product, $page ) use ( &$fired ) { + $fired[] = array( $product, $page ); + }, + 10, + 2 + ); + + // The suffix add_submenu_page() returned, whatever menu state earlier tests left behind. + $admin->enqueueSettingsScripts( get_plugin_page_hookname( 'viz-settings', Visualizer_Plugin::NAME ) ); + $admin->enqueueSettingsScripts( 'edit-post' ); + + $this->assertSame( array( array( VISUALIZER_DIRNAME, 'settings' ) ), $fired ); + } +}