Skip to content
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

Compat: Upgrade admin notices to use Notices module at runtime #11604

Merged
merged 16 commits into from
Nov 19, 2018

Conversation

aduth
Copy link
Member

@aduth aduth commented Nov 7, 2018

Related: #5975, #6388
Supersedes #5590
Closes #10448

This pull request seeks to try to seamlessly upgrade notices output via an admin_notices or all_admin_notices action server-side.

Implementation notes:

The flow here is:

  • Discover admin notices by .notice class
  • Convert to @wordpress/notices notice object
    • This occurs in edit-post, though in the future I think either this compatibility should (a) become unnecessary or (b) be moved somewhere more generic
  • Dispatch to create notice through @wordpress/notices
  • Removes the admin notice from the DOM

Testing instructions:

Here's a plugin if you need one:

demo-notice.zip

This will add a dismissible success notice to any admin screen.

Verify that upon visiting Gutenberg, a notice echo'd during admin_notices or all_admin_notices is displayed.

Pending tasks:

@aduth aduth added the Backwards Compatibility Issues or PRs that impact backwards compatability label Nov 7, 2018
@mcsf
Copy link
Contributor

mcsf commented Nov 8, 2018

Notice content is supported only as a plaintext string. Advanced markup is not supported. In not supporting non-plaintext, we can't truly close #10448, which includes an inline link. The notices module supports linkable "actions", but not interspersed with the plaintext. This ties in a bit with #9846, with the most direct solutions being one of either (a) allow elements as notice content or (b) pass notice content to a RawHTML component, neither of which is ideal in my mind.

Per Slack, I'd be OK with a compat-only way of providing raw content (__experimentalHTML), so something aligned with option b).

@aduth aduth added [Status] In Progress Tracking issues with work in progress [Package] Notices /packages/notices labels Nov 8, 2018
@aduth
Copy link
Member Author

aduth commented Nov 8, 2018

cc @desrosj

@aduth aduth force-pushed the update/legacy-notices branch from d653835 to ab75260 Compare November 8, 2018 16:34
@aduth
Copy link
Member Author

aduth commented Nov 8, 2018

I've updated the pull request to include support for the aforementioned __unstableHTML property on notices.

You can test with a revised example plugin, where the inline markup is now respected.

<?php

/**
 * Plugin name: Demo Notice
 */

function demo_notice_add() {
	echo '<div class="notice notice-success is-dismissible"><p>My <strong>notice</strong> text</p></div>';
}
add_action( 'admin_notices', 'demo_notice_add' );

Included are revisions to the coding standards document, as in discussing this with @nerrad (link requires registration), we came to agree that there's a subtle but important distinction between an experimental and an unstable API.

@aduth aduth removed the [Status] In Progress Tracking issues with work in progress label Nov 8, 2018
@aduth aduth force-pushed the update/legacy-notices branch from ab75260 to 35837cf Compare November 8, 2018 18:45
@desrosj
Copy link
Contributor

desrosj commented Nov 14, 2018

Sorry for the delay on this, @aduth. I have been traveling.

The functionality works great. Based on my testing, all notices output using the two specified filters that follow the current admin notice markup are converted to new Gutenberg notices correctly.

I tested this with all variations of supported notices, and they look great. Here is my slightly more exhaustive list: https://gist.github.com/desrosj/224863d7fb9fa9f4866ac5b2f6e15ebc

In testing the notice variations above, I did notice two issues, but I am not sure if they should be solved here or in a separate issue.

First, there are two types of notices currently supported in Core: .notice and .notice-alt. Currently, Gutenberg displays them the same.

Current admin notice styling:
screen shot 2018-11-13 at 10 22 55 pm

Admin notice styling in Gutenberg:
screen shot 2018-11-13 at 10 25 16 pm

Second, if admin notices are not dismissible, the editor can be rendered useless.
screen shot 2018-11-13 at 10 26 49 pm

It is not uncommon to have several notices in the admin, especially when the user has one or two plugins activated that have not yet been set up. I worry that this will render the editor unusable for some users. In the current state, any number of non-dismissible notices greater than one will hide the Title field.

Lastly, the order of the notices is reversed when converted. Is there any way to maintain the notice order? If a plugin uses an action priority of 999 to output their notice last, that behavior should be maintained.

@desrosj
Copy link
Contributor

desrosj commented Nov 14, 2018

I did some more testing today. Turns out there are two additional instances I had missed for supported admin notices. The styles for these instances are missing.

<div class="error"><p>My error notice text.</p></div>
<div class="updated"><p>My updated notice text.</p></div>

Warning and info notices are not currently supported this way (with .warning .notice).

I also started to look at some other ways plugins are using these core notice patterns. I found a few instances where notices had multiple paragraph tags in one notice.

<div class="updated"><p>Your action succeeded!</p><p>Here is direction for what to do next.</p></div>

screen shot 2018-11-14 at 2 46 39 pm

Gutenberg equivalent:
screen shot 2018-11-14 at 2 47 26 pm

Only the first paragraph is moved over in these instances.

It's also not uncommon to have buttons in a second paragraph, such as with WooCommerce.
screen shot 2018-11-14 at 2 56 58 pm

In Gutenberg:
screen shot 2018-11-14 at 3 00 41 pm

I'm starting to worry that this one is more complex than we thought. I still believe that this should be present in 5.0, but it seems we may have to make decisions about what is and is not supported.

This exercise has also made me feel strongly that a dev note should be published on make.wordpress.org/core detailing how a plugin can ensure compatibility of their notices in Gutenberg while maintaining backward compatibility.

@aduth
Copy link
Member Author

aduth commented Nov 14, 2018

First, there are two types of notices currently supported in Core: .notice and .notice-alt. Currently, Gutenberg displays them the same.

Forgive my ignorance: Can you explain or point me in a direction which explains what an "alt" notice is meant to be?

Second, if admin notices are not dismissible, the editor can be rendered useless.

This is good to note, and practically speaking could occur today in the editor. I think we'd either want to make it so that every notice must be dismissible, or that the notices are rendered in a way which pushes down the editor.

(could use some design feedback, cc @jasmussen ?)

Lastly, the order of the notices is reversed when converted. Is there any way to maintain the notice order?

I'm not positive on what basis it was reached, but the behavior of the notices implementation in Gutenberg is such that the notices which are added last are shown at the top of the list, which is consistent with what you've described.

The styles for these instances [.error, .updated] are missing.

Good catch. I suppose it would be good to add these. Tracking ad hoc variations from the core stylesheets is becoming a bit cumbersome 😕

https://github.com/WordPress/WordPress/blob/da7a80d67fea29c2badfc538bfc01c8a585f0cbe/wp-admin/css/common.css#L1344-L1346

I found a few instances where notices had multiple paragraph tags in one notice. [...] Only the first paragraph is moved over in these instances.

The reason I'd decided to target specifically the paragraph (wrongly assumed singular) previously was partly to avoid including the dismiss button. Maybe it would make more sense to explicitly target that for removal, and keep everything else intact verbatim.

@desrosj
Copy link
Contributor

desrosj commented Nov 15, 2018

Forgive my ignorance: Can you explain or point me in a direction which explains what an "alt" notice is meant to be?

As far as I know, it is just an alternate styling available.

This is good to note, and practically speaking could occur today in the editor. I think we'd either want to make it so that every notice must be dismissible, or that the notices are rendered in a way which pushes down the editor.

It can happen in the editor today, but the notices will not overlap the editor, it will push the title field and editor down for better or worse. I think replicating that in Gutenberg would be fine but wonder about the implications of having to scroll down to get to the editor.

In my opinion, we should not make non-dismissible notices dismissible. Usually, the notice is there and not dismissible for a reason (a persistent reminder to the user to perform an action).

I'm not positive on what basis it was reached, but the behavior of the notices implementation in Gutenberg is such that the notices which are added last are shown at the top of the list, which is consistent with what you've described.

Gotcha. That makes sense, but I think for the maximum backward compatibility we should reverse the list before passing the notices to API.

Good catch. I suppose it would be good to add these. Tracking ad hoc variations from the core stylesheets is becoming a bit cumbersome 😕

I am pretty sure my Gist has an exhaustive list now. I also added .notice-title example which just has larger text and a few icons that are possible that I added for completeness.

The reason I'd decided to target specifically the paragraph (wrongly assumed singular) previously was partly to avoid including the dismiss button. Maybe it would make more sense to explicitly target that for removal, and keep everything else intact verbatim.

Reversing the logic makes sense. Let's see how that works out.

@aduth
Copy link
Member Author

aduth commented Nov 16, 2018

It can happen in the editor today, but the notices will not overlap the editor, it will push the title field and editor down for better or worse.

By today, I meant specifically with the notices module. For example, running this code in the console:

[ ...Array( 5 ) ].forEach( () => wp.data.dispatch( 'core/notices' ).createInfoNotice( 'hello', { isDismissible: false } ) )

The "push down" behavior might take effect for server notices, but not for the ones we render natively in the editor. I think it'd probably be sensible to implement it this way anyways, as the overlap seems like it'd almost always be the undesirable behavior. It has an impact on design though.

@aduth
Copy link
Member Author

aduth commented Nov 16, 2018

Forgive my ignorance: Can you explain or point me in a direction which explains what an "alt" notice is meant to be?

As far as I know, it is just an alternate styling available.

If it serves no semantic purpose, I'm inclined to think it should just be made unsupported in the transition.

I think the same would apply to .notice-large.

@aduth
Copy link
Member Author

aduth commented Nov 16, 2018

I am pretty sure my Gist has an exhaustive list now. I also added .notice-title example which just has larger text and a few icons that are possible that I added for completeness.

I totally missed this in your original comment. This is great to work from. Thanks!

@aduth
Copy link
Member Author

aduth commented Nov 16, 2018

I'm going to add the Needs Accessibility Feedback label because I'm concerned of two things:

  • Should we announce the adapted notices? I expect no such announcement occurs for any other server-rendered notice. Thus, maybe we need an option for notice creation to disable the speaking behavior, or at least disabling it for the notices compatibility. Or maybe wp.a11y can be enhanced to avoid announcing anything which occurs immediately at page load.
  • Even if we were to speak something, what can we assume programmatically to be spoken for a notice which might contain many paragraphs? I'd started down the path of something like paragraphs.map( ( p ) => p.textContent.trim() ).join( ' ' ) but it feels a bit fragile.

@aduth aduth added the Needs Accessibility Feedback Need input from accessibility label Nov 16, 2018
@aduth aduth force-pushed the update/legacy-notices branch from 35837cf to c308c3e Compare November 16, 2018 18:24
@aduth
Copy link
Member Author

aduth commented Nov 16, 2018

I've rebased to resolve conflicts, and have pushed a number of revisions:

  • Account for .updated and .error notice classes (f9b44c5)
  • Use all markup of the notice (except the dismiss button) (234b58b)
  • Reverse order of server-rendered notices (c308c3e)

To the question of: "What should be spoken for notices?" The current state of the branch adds an option to disable spoken announcements for notices. (137b3bd) Upgraded notices will not be spoken. (234b58b)

To the question of: "What to do about overlapping undismissible notices?" The current state of the branch does nothing (yet). I posed the question in Slack (link requires registration) where there was some overwhelming feedback that all notices should be dismissible (until better broad support is implemented).

@aduth
Copy link
Member Author

aduth commented Nov 16, 2018

To the question of: "What to do about overlapping undismissible notices?" The current state of the branch does nothing (yet). I posed the question in Slack (link requires registration) where there was some overwhelming feedback that all notices should be dismissible (until better broad support is implemented).

Update: Continued discussion led to a different conclusion: Non-dismissible notices should remain non-dismissible, but should push down the rest of the editor such that they don't render it inoperable. Dismissible notices should remain floated above the editable area.

Terrible ASCII art:

+---------------------+
| Header              |
+----------------+----+
| Undismissible  |    |
+----------------+    |
| +------------+ |    |
| | Dismissible| |    |
| +------------+ |    |
|                |    |
|                |    |
|                |    |
|                |    |
+----------------+----+

I'm inclined to think that if agreeable, this should be done as a task separate to what's intended by the changes here, since it affects editor notices broadly irrespective of server-rendered compatibility.

desrosj added a commit to desrosj/gutenberg that referenced this pull request Nov 16, 2018
…n hook.

The new editor does not support the `edit_form_after_title` action hook. Because WordPress Core uses this hook to output the notice, it is not printed to the screen.

After WordPress#11604 is merged, legacy style admin notices (`<div class="notice">...notice content...</div>`) will be consumed by the Notices API and displayed. This change ensures that when WordPress#11604 is merged the privacy policy notice will appear again when editing the privacy policy page.
@desrosj desrosj mentioned this pull request Nov 16, 2018
4 tasks
@desrosj
Copy link
Contributor

desrosj commented Nov 16, 2018

Let me know when you are ready for a review, @aduth. Thanks for all the work on this!

One thing that I wanted to point out, though, is that #10448 is not closed by this issue without #11999. That notice is hooked to edit_form_after_title in WordPress core, which is not supported by the new editor. This means the notice is never output to the screen for the notices API to consume.

That PR will move it to admin_notices when the plugin is active so this PR can pass it into the Notices API.

@aduth
Copy link
Member Author

aduth commented Nov 16, 2018

I think it's ready for a proper review in its current form, with aforementioned caveat that we're not yet doing anything about undismissible notices blocking the editor.

The prior build failure was due to neglecting to rebuild the docs. Should hopefully be cleared up by e0960ff.

@aduth
Copy link
Member Author

aduth commented Nov 16, 2018

I'll remove the "Closes" signal from the original comment, to reflect the fact there is remaining work to be done.

@desrosj
Copy link
Contributor

desrosj commented Nov 17, 2018

From a testing perspective, this looks great. A few notes:

  • Looks like the .notice-title styles carried over with no issues.
  • In the current state, the -alt and icon styles would not carry over.
  • The notices are now showing in the same order as output serverside.

I wonder if dismissible notices covering the editor fields will be confusing for users on new posts or empty editor screens.

I defer the code review to someone stronger in Javascript.

@collimarco
Copy link

I use Wordpress 5.0 and this feature doesn't work.

I have a plugin with this simple code:

function pushpad_notices() {
	echo '<div class="notice notice-success is-dismissible"><p>My notice text</p></div>';
}
add_action( 'admin_notices', 'pushpad_notices' );

The test notice is displayed properly on all admin pages, except for the editor page! I don't see any notice there. What should I do?

@chrisvanpatten
Copy link
Contributor

@collimarco This was ultimately reverted in #12444 and restored to the original Gutenberg behaviour of hiding admin notices rendered through PHP. I hope in Phase 2 we can look at ways to improve this with a more reliable implementation!

@collimarco
Copy link

@chrisvanpatten Thanks for the reply. However I don't understand what I am supposed to do in order to display a notice at the moment. Can you give me an example? Or should I keep using admin_notices and simply wait that you fix it?

@aduth
Copy link
Member Author

aduth commented Dec 11, 2018

Hi @collimarco , for the moment the editor supports only notices created in JavaScript using the data module. More information about the data module (the wp-data script handle, made available at wp.data in the browser) and actions available specific to notices can be found at the following links:

In the future, there may be some patterns surrounding aggregating server-side notices for display in the editor, like discussed at the following links:

@Hube2
Copy link

Hube2 commented Jan 6, 2019

@aduth Do you know of any usable examples of using the documents you linked to?

@aduth
Copy link
Member Author

aduth commented Jan 7, 2019

@Hube2 I'm not personally aware of an example of a plugin which integrates with the notices module specifically. I've prompted for suggestions in WordPress Slack (link requires registration):

https://wordpress.slack.com/archives/C02QB2JS7/p1546872144246900

@opensaurusrex
Copy link

@aduth Will there also be added documentation to go along with that? Because I am finding the docs to be pretty much a case of ignore it, go straight to source code (which helps some but it could use more comments), hack at it and read the issues just incase the developers broke yet another feature because insert reason here.

Took me an hour of the above mentioned methods to figure out how to show HTML content of a notice. Main reason I was forced to do this is because of the missing Notices Data Handbook page linked in @wordpress/notices. This type of stuff is quite frustrating for a developer, since it slows me down. I am used to just jumping on PHP.net real quick, finding a fleshed out documentation and figuring out what API methods need to be called and moving on. Since I picked up WP dev, it's definitely been the opposite for me.

Thanks for any info!

@aduth
Copy link
Member Author

aduth commented Jan 21, 2019

Could you clarify your question, @opensaurusrex ? I'm sympathetic to the need for a sensible documentation reference. It's accurate to say documentation has suffered from the rapid development leading up to 5.0 . It's part of the reason for a concentrated effort in improved documentation:

https://make.wordpress.org/docs/2018/12/11/gutenberg-dev-docs-call-for-contributions/

Unfortunately the rapidly evolving documentation restructuring has had its own problems, as in the broken link you've referenced.

The corrected link is:

https://wordpress.org/gutenberg/handbook/designers-developers/developers/data/data-core-notices/

I've proposed a fix at #13409

Please feel free to raise these in issues as you encounter them.

@opensaurusrex
Copy link

@aduth When they finish the upgrade to the notices, will they also be updating the documentation to show users how to take advantage of it? I am having a hard time learning all of the new stuff because the documentation doesn't reflect what it's actually doing, and it doesn't show practical use cases for the components and/or features that are in documentation. I usually end up reading source code and making guesses on what has to be done.

Eg., I was able to figure out that wp.data.dispatch('core/notices').createErrorNotice("<p><strong>Error:</strong>...", {__unstableHTML: true}); allows me to include HTML, though I had to guess that from the name of the variables in source code and then figure out where the HTML goes, which ended up being where you put the regular string.

Also, if you notice in that link you shared with me the __unstableHTML option is not even mentioned. Is this due to it still being worked on and the documentation just being so far behind? And, I appreciate how you are trying to get the docs updated. If you guys need help documenting I would be willing to help as long as the information was provided to fulfill it.

@aduth
Copy link
Member Author

aduth commented Jan 22, 2019

It's not mentioned because unstable APIs are never documented, and should never be used, as they can and will be removed without notice. For all intents and purposes, this feature doesn't exist.

https://github.com/WordPress/gutenberg/blob/master/docs/contributors/coding-guidelines.md#experimental-apis

@opensaurusrex
Copy link

@aduth Ah okay. That answers the question I had regarding why it was prefixed like that. Though, whoever wrote the code for that feature obviously forgot to add the warning to not use it. I am starting to think I should just stick with WordPress 4.9 because it seems like they released an unfinished product into the wild. Maybe in a year or two it might be worth coming back to see if it's done yet. Feels like an extended beta test.

@danielbachhuber
Copy link
Member

Even though the __unstableHTML API is completely unsupported, voids the warranty and could be removed at any time, I needed to be able to create a notice with some basic HTML. Here's how I did so, cribbing from this pull request.

First, I created an admin-notices.js file that only targets my .tasty-recipes-notice selector:

/**
 * WordPress dependencies
 */
const {
	dispatch,
} = wp.data;

const NOTICE_SELECTOR = '.tasty-recipes-notice';

/**
 * Returns an array of admin notice Elements.
 *
 * @return {Element[]} Admin notice elements.
 */
function getAdminNotices() {
	return [ ...document.querySelectorAll( `#wpbody-content ${ NOTICE_SELECTOR }` ) ].reverse();
}

/**
 * Given an admin notice Element, returns the relevant notice content HTML.
 *
 * @param {Element} element Admin notice element.
 *
 * @return {Element} Upgraded notice HTML.
 */
function getNoticeHTML( element ) {
	const fragments = [];

	for ( const child of element.childNodes ) {
		if ( child.nodeType !== window.Node.ELEMENT_NODE ) {
			const value = child.nodeValue.trim();
			if ( value ) {
				fragments.push( child.nodeValue );
			}
		} else if ( ! child.classList.contains( 'notice-dismiss' ) ) {
			fragments.push( child.outerHTML );
		}
	}

	return fragments.join( '' );
}

/**
 * Converts existing notices to block editor notices.
 */
export default function convertNotices() {
	const { createInfoNotice } = dispatch( 'core/notices' );
	getAdminNotices().forEach( ( element ) => {
		// Convert and create.
		const content = getNoticeHTML( element );
		const isDismissible = element.classList.contains( 'is-dismissible' );
		createInfoNotice( content, {
			speak: false,
			__unstableHTML: true,
			isDismissible,
		} );

		// Remove (now-redundant) admin notice element.
		element.parentNode.removeChild( element );
	} );
}

Then, I imported it into my bootstrap index.js file and hooked it onto window.load:

import convertNotices from './admin-notices';

window.addEventListener( 'load', () => {
	convertNotices();
} );

@aduth
Copy link
Member Author

aduth commented Jan 23, 2019

The topic of supporting raw HTML in notices was discussed in today's #core-editor meeting (link requires registration)

https://wordpress.slack.com/archives/C02QB2JS7/p1548255146244100

Recap:

  • Needs use cases
  • Will not prefer to allow raw HTML, configuration-driven instead

Note that __unstableHTML is/was slated for removal as part of #12440 .

Future efforts may be made to make unstable APIs more unreachable (e.g. randomized property names). Seriously, don't use them.

Added to the agenda for next Tuesday's #core-js meeting:

https://docs.google.com/document/d/1HPcT96J3ysm3fVDixELfmHkWneA0ir7yHwhgKORGPNA/edit

@danielbachhuber
Copy link
Member

For posterity, here's my particular use-case:

image

It looks like I can achieve this with notice actions, so I'm going to refactor towards that.

@danielbachhuber
Copy link
Member

If you care to help improve the documentation, I've created #13592 as a follow-up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Backwards Compatibility Issues or PRs that impact backwards compatability [Package] Notices /packages/notices [Priority] High Used to indicate top priority items that need quick attention
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Help notice displayed on Privacy Policy page missing in Gutenberg