From 98965fddae1adf86729b2e5ac6024137fe4a2332 Mon Sep 17 00:00:00 2001 From: Dovid Levine Date: Fri, 6 Mar 2026 00:40:22 +0200 Subject: [PATCH 1/2] fix: Remediate PHPCS lints --- inc/Modules/Core/Assets.php | 4 +--- inc/Modules/Rest/Governing_Data_Controller.php | 5 ++--- inc/Modules/Rest/Governing_Data_Handler.php | 5 ++--- inc/Modules/Rest/Search_Controller.php | 5 ++--- inc/Modules/Search/Post_Record.php | 2 +- inc/Modules/Search/Search.php | 13 +++++-------- inc/Modules/Search/Settings.php | 8 ++++++-- inc/Modules/Search/Watcher.php | 4 +++- inc/Modules/Settings/Settings.php | 4 +++- 9 files changed, 25 insertions(+), 25 deletions(-) diff --git a/inc/Modules/Core/Assets.php b/inc/Modules/Core/Assets.php index 2458059..84ca819 100644 --- a/inc/Modules/Core/Assets.php +++ b/inc/Modules/Core/Assets.php @@ -134,10 +134,8 @@ public function register_assets(): void { /** * Add scripts and styles to the page. - * - * @param string $hook_suffix Admin page name. */ - public function enqueue_scripts( $hook_suffix ): void { + public function enqueue_scripts(): void { // @todo Only enqueue on OneSearch admin pages. wp_enqueue_style( self::ADMIN_STYLES_HANDLE ); } diff --git a/inc/Modules/Rest/Governing_Data_Controller.php b/inc/Modules/Rest/Governing_Data_Controller.php index 8f286c8..56a17f1 100644 --- a/inc/Modules/Rest/Governing_Data_Controller.php +++ b/inc/Modules/Rest/Governing_Data_Controller.php @@ -1,13 +1,12 @@ post_content ); } catch ( \Throwable $e ) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- @todo Surface this better with a Logger class. diff --git a/inc/Modules/Search/Search.php b/inc/Modules/Search/Search.php index 344072e..1f78c26 100644 --- a/inc/Modules/Search/Search.php +++ b/inc/Modules/Search/Search.php @@ -56,7 +56,7 @@ public function register_hooks(): void { // Author data. add_filter( 'get_the_author_display_name', [ $this, 'get_post_author' ], 10 ); - add_filter( 'author_link', [ $this, 'get_post_author_link' ], 10, 3 ); + add_filter( 'author_link', [ $this, 'get_post_author_link' ], 10 ); add_filter( 'get_avatar_url', [ $this, 'get_post_author_avatar' ], 10 ); // Term and taxonomy link handling for remote objects. @@ -67,7 +67,7 @@ public function register_hooks(): void { add_filter( 'wp_get_post_terms', [ $this, 'get_post_terms' ], 10, 3 ); // Block-theme compatibility: fix remote permalinks/excerpts in rendered blocks. - add_filter( 'render_block', [ $this, 'filter_render_block' ], 10, 3 ); + add_filter( 'render_block', [ $this, 'filter_render_block' ], 10, 2 ); } /** @@ -166,13 +166,11 @@ public function get_post_author( $author_name ) { /** * Author link mapping for remote posts. * - * @param string $author_link Default author link. - * @param int $author_id Author ID (negative for remote). - * @param string|null $author_nicename The author's nicename if provided by the filter. + * @param string $author_link Default author link. * * @return string */ - public function get_post_author_link( $author_link, $author_id, $author_nicename = null ) { + public function get_post_author_link( $author_link ) { global $wp_query, $post; if ( ! $this->is_search_enabled() || ! $wp_query instanceof \WP_Query || ! $this->should_filter_query( $wp_query ) ) { @@ -325,11 +323,10 @@ public function get_post_terms( $terms, $post_id, $taxonomy ) { * * @param string $block_content Rendered block HTML. * @param array $block Block data. - * @param \WP_Block $instance Block instance. * * @return string */ - public function filter_render_block( $block_content, $block, $instance ) { + public function filter_render_block( $block_content, $block ) { global $post; if ( ! $this->is_search_enabled() || ! $post instanceof \WP_Post || (int) $post->ID >= 0 || empty( $post->guid ) ) { diff --git a/inc/Modules/Search/Settings.php b/inc/Modules/Search/Settings.php index f17c1c7..138e349 100644 --- a/inc/Modules/Search/Settings.php +++ b/inc/Modules/Search/Settings.php @@ -166,10 +166,12 @@ public function register_settings(): void { /** * Deletes Algolia index when site type is changed to consumer. * + * @internal Hook callback + * * @param mixed $old_value The old value. * @param mixed $new_value The new value. */ - public function on_site_type_change( $old_value, $new_value ): void { + public function on_site_type_change( $old_value, $new_value ): void { // phpcs:ignore SlevomatCodingStandard.Functions.UnusedParameter.UnusedParameter if ( Admin_Settings::SITE_TYPE_CONSUMER !== $new_value ) { return; } @@ -252,11 +254,13 @@ static function ( $site_url ) { /** * Purges the Governing_Data_Handler cache when a setting update triggers. * + * @internal Hook callback + * * @param mixed $old_value The old value. * @param mixed $new_value The new value. * @param string $option The option name. */ - public function purge_cache_on_update( $old_value, $new_value, $option ): void { + public function purge_cache_on_update( $old_value, $new_value, $option ): void { // phpcs:ignore SlevomatCodingStandard.Functions.UnusedParameter.UnusedParameter match ( $option ) { self::OPTION_GOVERNING_ALGOLIA_CREDENTIALS, self::OPTION_GOVERNING_SEARCH_SETTINGS, diff --git a/inc/Modules/Search/Watcher.php b/inc/Modules/Search/Watcher.php index 2ff498c..eb3c295 100644 --- a/inc/Modules/Search/Watcher.php +++ b/inc/Modules/Search/Watcher.php @@ -29,11 +29,13 @@ public function register_hooks(): void { /** * Triggered when a post's status changes (e.g., publish, update, trash, etc.) * + * @internal Hook callback + * * @param string $new_status The new post status. * @param string $old_status The previous post status. * @param \WP_Post $post The post object. */ - public function on_post_transition( $new_status, $old_status, $post ): void { + public function on_post_transition( $new_status, $old_status, $post ): void { // phpcs:ignore SlevomatCodingStandard.Functions.UnusedParameter.UnusedParameter if ( ! $post instanceof \WP_Post || ! $this->is_post_type_indexable( (string) $post->post_type ) ) { return; } diff --git a/inc/Modules/Settings/Settings.php b/inc/Modules/Settings/Settings.php index 581048e..8c1a5ec 100644 --- a/inc/Modules/Settings/Settings.php +++ b/inc/Modules/Settings/Settings.php @@ -165,10 +165,12 @@ public function register_settings(): void { /** * Ensures the API key is generated when the site type changes to 'consumer'. * + * @internal Hook callback + * * @param mixed $old_value The old value. * @param mixed $new_value The new value. */ - public function on_site_type_change( $old_value, $new_value ): void { + public function on_site_type_change( $old_value, $new_value ): void { // phpcs:ignore SlevomatCodingStandard.Functions.UnusedParameter.UnusedParameter if ( self::SITE_TYPE_CONSUMER !== $new_value ) { return; } From b0d038dfea809f836221272ad5abe6adfcefd7b7 Mon Sep 17 00:00:00 2001 From: Dovid Levine Date: Mon, 9 Mar 2026 16:37:15 +0200 Subject: [PATCH 2/2] fix: Remediate eslint + ts smells (#148) * fix: remediate eslint and ts errors * ci: fix playwright path * fix: phpstan errors (#149) --- assets/src/admin/onboarding/page.tsx | 15 ++++++---- assets/src/admin/search/index.js | 3 +- .../src/components/SiteIndexableEntities.js | 2 +- assets/src/components/SiteModal.tsx | 2 +- assets/src/components/SiteSearchSettings.js | 20 ++++++++----- assets/src/components/SiteSettings.tsx | 8 ++--- assets/src/js/utils.ts | 2 +- inc/Modules/Search/Search.php | 2 +- phpstan.neon.dist | 2 ++ phpstan/stubs/wordpress-extended.php | 29 +++++++++++++++++++ playwright.config.ts | 7 ++--- 11 files changed, 64 insertions(+), 28 deletions(-) create mode 100644 phpstan/stubs/wordpress-extended.php diff --git a/assets/src/admin/onboarding/page.tsx b/assets/src/admin/onboarding/page.tsx index f085d7c..389da98 100644 --- a/assets/src/admin/onboarding/page.tsx +++ b/assets/src/admin/onboarding/page.tsx @@ -27,9 +27,12 @@ interface NoticeState { message: string; } -// WordPress provides snake_case keys here. Using them intentionally. -// eslint-disable-next-line camelcase -const { nonce, setup_url, site_type } = window.OneSearchOnboarding; +// WordPress provides snake_case keys here. Rename to camelCase for local use. +const { + nonce, + setup_url: setupUrl, + site_type: initialSiteType, +} = window.OneSearchOnboarding; /** * Create NONCE middleware for apiFetch @@ -66,7 +69,7 @@ const SiteTypeSelector = ( { const OnboardingScreen = () => { const [ siteType, setSiteType ] = useState< SiteType | '' >( - site_type || '' + initialSiteType || '' ); const [ notice, setNotice ] = useState< NoticeState | null >( null ); const [ isSaving, setIsSaving ] = useState( false ); @@ -106,8 +109,8 @@ const OnboardingScreen = () => { setSiteType( settings.onesearch_site_type ); // Redirect user to setup page. - if ( setup_url ) { - window.location.href = setup_url; + if ( setupUrl ) { + window.location.href = setupUrl; } } ); } catch { diff --git a/assets/src/admin/search/index.js b/assets/src/admin/search/index.js index b7f8c59..c38da38 100644 --- a/assets/src/admin/search/index.js +++ b/assets/src/admin/search/index.js @@ -182,10 +182,11 @@ const OneSearchSettingsPage = () => { body: JSON.stringify( { sites_data: updated } ), } ); if ( ! response.ok ) { + /* eslint-disable-next-line no-console */ console.error( 'Error saving Brand site:', response.statusText - ); // eslint-disable-line no-console + ); return response; } diff --git a/assets/src/components/SiteIndexableEntities.js b/assets/src/components/SiteIndexableEntities.js index 847951d..e43f9b6 100644 --- a/assets/src/components/SiteIndexableEntities.js +++ b/assets/src/components/SiteIndexableEntities.js @@ -96,7 +96,7 @@ const SiteIndexableEntities = ( { ), } ); } - }, [] ); + }, [ setNotice ] ); useEffect( () => { getIndexableEntities(); diff --git a/assets/src/components/SiteModal.tsx b/assets/src/components/SiteModal.tsx index 00e61e0..cf9de38 100644 --- a/assets/src/components/SiteModal.tsx +++ b/assets/src/components/SiteModal.tsx @@ -179,7 +179,7 @@ const SiteModal = ( { } ); setShowNotice( true ); } - } catch ( error ) { + } catch { setErrors( { ...newErrors, message: __( diff --git a/assets/src/components/SiteSearchSettings.js b/assets/src/components/SiteSearchSettings.js index 221b271..778e70f 100644 --- a/assets/src/components/SiteSearchSettings.js +++ b/assets/src/components/SiteSearchSettings.js @@ -17,7 +17,7 @@ import { __ } from '@wordpress/i18n'; /** * External dependencies */ -import { useState, useEffect } from 'react'; +import { useState, useEffect, useCallback } from 'react'; /** * Internal dependencies @@ -77,11 +77,14 @@ const SiteSearchSettings = ( { ]; // Check if site has indexable entities. - const siteHasEntities = ( url ) => { - const normalizedUrl = trailingslashit( url ); - const entities = indexableEntities[ normalizedUrl ] || []; - return Array.isArray( entities ) && entities.length > 0; - }; + const siteHasEntities = useCallback( + ( url ) => { + const normalizedUrl = trailingslashit( url ); + const entities = indexableEntities[ normalizedUrl ] || []; + return Array.isArray( entities ) && entities.length > 0; + }, + [ indexableEntities ] + ); // Auto-save search setting when entities are removed. useEffect( () => { @@ -144,7 +147,8 @@ const SiteSearchSettings = ( { } ); } ); } - }, [ indexableEntities ] ); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [ indexableEntities, setNotice, siteHasEntities ] ); // Load existing search settings useEffect( () => { @@ -174,7 +178,7 @@ const SiteSearchSettings = ( { setLoading( false ); setLocalNotice( null ); } ); - }, [ reloadKey ] ); + }, [ reloadKey, setNotice ] ); // Toggle Algolia for a site const handleSiteToggle = ( url, enabled ) => { diff --git a/assets/src/components/SiteSettings.tsx b/assets/src/components/SiteSettings.tsx index 6ec5070..8cc2503 100644 --- a/assets/src/components/SiteSettings.tsx +++ b/assets/src/components/SiteSettings.tsx @@ -51,7 +51,7 @@ const SiteSettings = () => { } const data = await response.json(); setApiKey( data?.secret_key || '' ); - } catch ( error ) { + } catch { setNotice( { type: 'error', message: __( @@ -96,7 +96,7 @@ const SiteSettings = () => { ), } ); } - } catch ( error ) { + } catch { setNotice( { type: 'error', message: __( @@ -126,7 +126,7 @@ const SiteSettings = () => { } const data = await response.json(); setGoverningSite( data?.governing_site_url || '' ); - } catch ( error ) { + } catch { setNotice( { type: 'error', message: __( @@ -160,7 +160,7 @@ const SiteSettings = () => { 'onesearch' ), } ); - } catch ( error ) { + } catch { setNotice( { type: 'error', message: __( diff --git a/assets/src/js/utils.ts b/assets/src/js/utils.ts index c78a940..742d859 100644 --- a/assets/src/js/utils.ts +++ b/assets/src/js/utils.ts @@ -25,7 +25,7 @@ export const isValidUrl = ( url: string ): boolean => { try { const parsedUrl = new URL( url ); return isURL( parsedUrl.href ); - } catch ( e ) { + } catch { return false; } }; diff --git a/inc/Modules/Search/Search.php b/inc/Modules/Search/Search.php index 1f78c26..1c86492 100644 --- a/inc/Modules/Search/Search.php +++ b/inc/Modules/Search/Search.php @@ -38,7 +38,7 @@ final class Search implements Registrable { * * @var bool|null */ - private ?bool $is_search_enabled; + private ?bool $is_search_enabled = null; /** * {@inheritDoc} diff --git a/phpstan.neon.dist b/phpstan.neon.dist index e6a6409..686cc88 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -21,6 +21,8 @@ parameters: max: 80500 bootstrapFiles: - onesearch.php + stubFiles: + - phpstan/stubs/wordpress-extended.php paths: - onesearch.php - uninstall.php diff --git a/phpstan/stubs/wordpress-extended.php b/phpstan/stubs/wordpress-extended.php new file mode 100644 index 0000000..67fb99d --- /dev/null +++ b/phpstan/stubs/wordpress-extended.php @@ -0,0 +1,29 @@ + $onesearch_algolia_highlights Highlighted search snippets from Algolia. + * @property string $onesearch_site_url URL of the site this post belongs to. + * @property string $onesearch_site_name Name of the site this post belongs to. + * @property string $onesearch_remote_post_author_display_name Remote author display name. + * @property string $onesearch_remote_post_author_link Remote author posts URL. + * @property string $onesearch_remote_post_author_gravatar Remote author avatar URL. + * @property int $onesearch_original_id Original post ID on remote site. + * @property array $onesearch_remote_taxonomies Taxonomies from remote site. + */ + class WP_Post { + } +} diff --git a/playwright.config.ts b/playwright.config.ts index 1b6111f..44301b8 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -4,10 +4,7 @@ import { defineConfig, type PlaywrightTestConfig } from '@playwright/test'; import path from 'path'; -const artifactsPath = path.join( - process.cwd(), - 'tests/_output' -); +const artifactsPath = path.join( process.cwd(), 'tests/_output/e2e' ); // Ensure WP artifacts (and storage-state) are written into tests/_output process.env[ 'WP_ARTIFACTS_PATH' ] = artifactsPath; @@ -24,7 +21,7 @@ const baseConfig = const config = defineConfig( { ...baseConfig, testDir: './tests/e2e', - outputDir: './tests/_output', + outputDir: './tests/_output/e2e', } ); export default config;