Spinners and dismissible admin notices in 4.2

There are two UI component changes in 4.2 aimed at better experiences moving forward that may affect plugin and theme authors. The first is the spinner element, which does come with a non-critical visual breaking change. The second is admin notices, which are an enhancement and do not affect current implementations.

Core’s spinner is implemented using the .spinner class. Up until now, spinners have been hidden using display: none and then toggled using jQuery’s .show()/.hide() methods. While this works, it has two fundamental problems: it ties us to jQuery-specific helpers, and more importantly, does not reserve the space for the spinner when hidden, leading to elements moving around on the screen whenever the spinner would toggle. The more appropriate solution would be to use CSS’s visibility property, which does reserve the visual space, and control that visual behavior via a class so that any future changes to CSS are inherited by anybody using that component.

To that end, to show a spinner, you should now add a class of .is-active to the spinner element, and remove that class when it’s no longer active. This state-communicating naming convention is a part of some of our longer-term goals when it comes to semantic markup, so also take note of that. The breakage here is that spinners will no longer show using jQuery’s .show() method, as all it does is set an inline CSS display property, and so you will need to account for that going forward. The best thing to do would be to update to toggling the class as noted, and if maintaining compatibility in the short term with older versions of WordPress is a concern, detect the version and inject CSS into admin_head that applies display: inline-block to .spinner.is-active. There are other methods for handling version compatibility as well, but this is likely to be the method that is most maintainable and easy to immediately understand. Work on this was handled in #22839.

The second UI component that we’ve improved in a more visible manner is admin notices. Admin notices are often a source of confusion – if you publish a post and then refresh the edit screen, you’ll still get the notice that you’ve published the post, leading you to wonder if you’ve published it twice or what exactly is going on. They’re also distracting, takes up precious space, and can cause visual fatigue, leading to users ignoring notices that really do need their attention. So, we’ve done two things: one, we’ve made the vast majority of core notices user-dismissible (#31233), and two, we’ve also made sure those notices won’t come back when you refresh the page and have JavaScript on/working (#23367).

Any notice can now be made dismissible by ensuring the it has the classes .notice and .is-dismissible (recognize that naming convention?). Core handles adding the close button and removing the notice for you. However, for the best possible user experience, you should ensure that those notices will not come back on a page refresh or when navigating to another page. There are two different paths for this. The first applies to notices that are added when a query arg is present in the URL, such as message=6. Core will now remove certain query args and use JS to replace the URL in the browser with that “cleaned up” version. By default, core handles 'message', 'settings-updated', 'saved', 'update', 'updated','activated', 'activate', 'deactivate', 'locked', 'deleted', 'trashed', 'untrashed', 'enabled', 'disabled', 'skipped', 'spammed', and 'unspammed'. To add (or remove) items to this array to accommodate your needs, use the removable_query_args filter.

The second path, for notices that persist across different page loads, is to bind to the click event on the .notice-dismiss element in your own notice and trigger whatever it is your plugin may need to do to remember that the notice has been dismissed, such as storing a site or user option using Ajax. A note of caution that in an ideal scenario, core would eventually provide a framework for persistently dismissible notices that are not tied to query args, so be prepared for future changes if you choose to use this method.

#4-2, #dev-notes