Make WordPress Core

Opened 3 years ago

Last modified 5 months ago

#54568 new defect (bug)

WordPress admin overwrite JS history.state

Reported by: maximeschoeni's profile maximeschoeni Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version:
Component: General Keywords: has-patch
Focuses: javascript Cc:

Description

WordPress admin is injecting a piece of javascript at runtime (https://developer.wordpress.org/reference/functions/wp_admin_canonical_url/) that prevent accessing history.state. This is annoying because you cannot use history.pushState() and history.replaceState() functions properly in javascript.

Reproduce the bug:

  1. Navigate to any wp admin page and open the browser developer console
  2. Enter window.history.replaceState({name: "hello"}, null) in console
  3. Navigate to any other page
  4. Go back and enter history.state // result -> null

Problem:
The code overwrites any history.state with null value:

window.history.replaceState( null, null, document.getElementById( 'wp-admin-canonical' ).href + window.location.hash );

Solution:
Replace null value by window.history.state (which also default to null):

window.history.replaceState( window.history.state, null, document.getElementById( 'wp-admin-canonical' ).href + window.location.hash );

The fix is very easy and has no side effect.

Attachments (1)

patch.diff (656 bytes) - added by maximeschoeni 3 years ago.

Download all attachments as: .zip

Change History (7)

@maximeschoeni
3 years ago

#1 @kevin940726
3 years ago

The change makes sense to me!

#2 @adamsilverstein
3 years ago

@maximeschoeni Thanks for the bug report.

Can you describe the use case for why you want to access history.state in wp-admin?

The original code here was introduced for https://core.trac.wordpress.org/ticket/23367

#3 @maximeschoeni
3 years ago

Quite a specific thing, I needed a modal to open in a popup and the modal have different states and I thought it was nice if you can navigate between states using browser history... Actually there are different ways (probably betters) to do than storing things in history.state, but I was curious why it didn't work. I understand the purpose of this piece of javascript but I see no reason why it has to overwrite the history.state, and it rather sounds like a bug.

#4 @audrasjb
3 years ago

  • Version trunk deleted

Hello, thanks for reporting this ticket. It appears this issue wasn't introduced in WP 5.9, so I'm removing the trunk version from the ticket.

#5 @findkit
6 months ago

Hi, this affects us as well. Findkit Search provides a plugin for WordPress which can inject our search interface to the wp-admin as well. It uses history.state to preserve scroll position when user navigates back to it from a search result. Since the history.state is forced to be null on wp-admin, this feature is broken and there's really no reasonable workarounds.

The proposed patch seems reasonable to me.

--
Esa-Matti Suuronen

Last edited 6 months ago by findkit (previous) (diff)

#6 @findkit
5 months ago

Found a workaround with a monkey patch. Inject this JS early in the admin_head action:

const original = history.replaceState;
history.replaceState = function findkitReplaceStatePatch(state, unused, url) {
    const canonical = document.getElementById('wp-admin-canonical').href + window.location.hash;
    if (state === null && url === canonical) {
        original.call(history, history.state, unused, url);
        history.replaceState = original;
    } else {
        original.call(history, state, unused, url);
    }
}

it overrides the existing replaceState function and detects the invalid call and recalls it the original function with history.state as the first param. Afterwards it restores the original function.

Our full implementation is here:
https://github.com/findkit/wp-findkit/blob/b6b2bead0a29664fefb14a6088eab197be73aa06/src/BugFixWpAdminHistoryState.php

--
Esa-Matti Suuronen

Note: See TracTickets for help on using tickets.