-
-
Notifications
You must be signed in to change notification settings - Fork 79
fix(tours): honour stripped legacy tour setting keys #1271
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -321,6 +321,41 @@ | |
| } | ||
| } | ||
|
|
||
| /** | ||
| * Test is_tour_finished reads legacy stripped keys from user settings meta. | ||
| * | ||
| * Regression test for users who dismissed hyphenated tours before the tour ID | ||
| * normalisation fix. WordPress could persist keys with hyphens stripped (for | ||
| * example, wu_tour_checkoutformlist), while newer code looks for the | ||
| * underscore-normalised key (wu_tour_checkout_form_list). The meta fallback | ||
| * must recognise the stripped legacy shape and backfill the new user meta flag. | ||
| */ | ||
| public function test_is_tour_finished_reads_stripped_legacy_user_settings_meta(): void { | ||
|
|
||
| $instance = $this->get_instance(); | ||
|
|
||
| $user_id = self::factory()->user->create(['role' => 'administrator']); | ||
| wp_set_current_user($user_id); | ||
|
|
||
| $reflection = new \ReflectionClass($instance); | ||
| $is_finished = $reflection->getMethod('is_tour_finished'); | ||
| $is_finished->setAccessible(true); | ||
| $get_meta_key = $reflection->getMethod('get_meta_key'); | ||
| $get_meta_key->setAccessible(true); | ||
| $get_legacy_keys = $reflection->getMethod('get_legacy_setting_keys'); | ||
| $get_legacy_keys->setAccessible(true); | ||
|
|
||
| $meta_key = $get_meta_key->invoke($instance, 'checkout-form-list'); | ||
|
|
||
| update_user_option($user_id, 'user-settings', 'wu_tour_checkoutformlist=1', false); | ||
|
|
||
| $this->assertSame('wu_tour_checkoutformlist=1', get_user_option('user-settings', $user_id)); | ||
| $this->assertContains('wu_tour_checkoutformlist', $get_legacy_keys->invoke($instance, 'checkout-form-list')); | ||
|
|
||
| $this->assertTrue($is_finished->invoke($instance, 'checkout-form-list', $user_id)); | ||
| $this->assertSame('1', get_user_meta($user_id, $meta_key, true)); | ||
|
Comment on lines
+350
to
+356
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
rg -n -C3 "wp-settings-|_updated_user_settings|test_is_tour_finished_falls_back_to_legacy_user_setting|test_is_tour_finished_reads_stripped_legacy_user_settings_meta" tests/WP_Ultimo/UI/Tours_Test.phpRepository: Ultimate-Multisite/ultimate-multisite Length of output: 3005 🏁 Script executed: #!/bin/bash
set -euo pipefail
nl -ba tests/WP_Ultimo/UI/Tours_Test.php | sed -n '320,390p'Repository: Ultimate-Multisite/ultimate-multisite Length of output: 124 🏁 Script executed: #!/bin/bash
set -euo pipefail
cat -n tests/WP_Ultimo/UI/Tours_Test.php | sed -n '320,390p'Repository: Ultimate-Multisite/ultimate-multisite Length of output: 3274 🏁 Script executed: #!/bin/bash
set -euo pipefail
rg -n "function is_tour_finished" -S . --glob='*.php'Repository: Ultimate-Multisite/ultimate-multisite Length of output: 168 🏁 Script executed: #!/bin/bash
set -euo pipefail
sed -n '130,260p' inc/ui/class-tours.phpRepository: Ultimate-Multisite/ultimate-multisite Length of output: 3570 🏁 Script executed: #!/bin/bash
set -euo pipefail
rg -n "\$_COOKIE\[['\"]wp-settings-'|_updated_user_settings|wp-settings-" tests/WP_Ultimo/UI/Tours_Test.phpRepository: Ultimate-Multisite/ultimate-multisite Length of output: 637 🏁 Script executed: #!/bin/bash
set -euo pipefail
cat -n tests/WP_Ultimo/UI/Tours_Test.php | sed -n '260,340p'Repository: Ultimate-Multisite/ultimate-multisite Length of output: 3999 🏁 Script executed: #!/bin/bash
rg -n -C3 "wp-settings-|_updated_user_settings|test_is_tour_finished_falls_back_to_legacy_user_setting|test_is_tour_finished_reads_stripped_legacy_user_settings_meta" tests/WP_Ultimo/UI/Tours_Test.phpRepository: Ultimate-Multisite/ultimate-multisite Length of output: 3005 Clear
Proposed fix+ $cookie_name = 'wp-settings-' . $user_id;
+ $prior_cookie = $_COOKIE[ $cookie_name ] ?? null; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- test stash, no user input.
+ $prior_updated_settings = $GLOBALS['_updated_user_settings'] ?? null;
+ unset($_COOKIE[ $cookie_name ]);
+ $GLOBALS['_updated_user_settings'] = null;
+
- update_user_option($user_id, 'user-settings', 'wu_tour_checkoutformlist=1', false);
-
- $this->assertSame('wu_tour_checkoutformlist=1', get_user_option('user-settings', $user_id));
- $this->assertContains('wu_tour_checkoutformlist', $get_legacy_keys->invoke($instance, 'checkout-form-list'));
-
- $this->assertTrue($is_finished->invoke($instance, 'checkout-form-list', $user_id));
- $this->assertSame('1', get_user_meta($user_id, $meta_key, true));
+ try {
+ update_user_option($user_id, 'user-settings', 'wu_tour_checkoutformlist=1', false);
+
+ $this->assertSame('wu_tour_checkoutformlist=1', get_user_option('user-settings', $user_id));
+ $this->assertContains('wu_tour_checkoutformlist', $get_legacy_keys->invoke($instance, 'checkout-form-list'));
+
+ $this->assertTrue($is_finished->invoke($instance, 'checkout-form-list', $user_id));
+ $this->assertSame('1', get_user_meta($user_id, $meta_key, true));
+ } finally {
+ if (null === $prior_cookie) {
+ unset($_COOKIE[ $cookie_name ]);
+ } else {
+ $_COOKIE[ $cookie_name ] = $prior_cookie;
+ }
+ $GLOBALS['_updated_user_settings'] = $prior_updated_settings;
+ }🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| /** | ||
| * Test enqueue_scripts uses wp_add_inline_script on 'underscore', not wu-admin. | ||
| * | ||
|
|
@@ -336,7 +371,7 @@ | |
|
|
||
| // Register 'underscore' if not already registered (test environment may not have it). | ||
| if ( ! wp_script_is('underscore', 'registered')) { | ||
| wp_register_script('underscore', false, [], false, false); | ||
|
Check warning on line 374 in tests/WP_Ultimo/UI/Tours_Test.php
|
||
| } | ||
|
|
||
| // Inject a tour so enqueue_scripts() proceeds. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
In WordPress core, does get_user_setting( $name, $default ) read only the current user's wp-settings cookie/cache, or can it resolve settings for an arbitrary user ID? Please include the function signature and a short summary of its lookup behavior.💡 Result:
Function signature: get_user_setting( $name, $default_value = false) [1] Short summary of lookup behavior (WordPress core): - get_user_setting calls get_all_user_settings, then returns the setting value from the returned array for key $name, or returns $default_value if the key is not present. [1][2] - get_all_user_settings only resolves settings for the current request’s “current user” (it uses get_current_user_id). If there is no current user ID, it returns an empty array. [2] - When a cookie is available, get_all_user_settings reads the user-settings cookie named wp-settings-{user_id} from $_COOKIE (and if not present, it falls back to the user option user-settings in the database for that same $user_id). [2] Answer to your question: In WordPress core, get_user_setting($name, $default_value) does not let you resolve settings for an arbitrary user ID. It looks up settings only for the current user ID for the current request, and it prefers the current browser’s wp-settings-{user_id} cookie (with a database fallback if the cookie is absent) rather than an arbitrary user ID argument. [2][1]
Citations:
Scope
get_user_setting()to the requested user to prevent cross-user legacy backfillget_user_setting( $name, $default_value = false )is backed byget_all_user_settings(), which resolves settings for the current request’s current user (cookiewp-settings-{current_user_id}with DB fallback). Sinceis_legacy_tour_finished($id, $user_id)callsget_user_setting()without using$user_id, it can read the current browser user’s legacy cookie while then backfilling meta for the passed$user_id.Proposed fix
protected function is_legacy_tour_finished($id, $user_id) { - foreach ($this->get_legacy_setting_keys($id) as $setting_key) { - if (get_user_setting($setting_key, false)) { - return true; - } - } + if (get_current_user_id() === (int) $user_id) { + foreach ($this->get_legacy_setting_keys($id) as $setting_key) { + if (get_user_setting($setting_key, false)) { + return true; + } + } + } $stored_settings = get_user_option('user-settings', $user_id);📝 Committable suggestion
🤖 Prompt for AI Agents