Saving a post in WP 6.4 converts content to Classic block
-
Hi! After updating to WP 6.4 I started experiencing the following issue on all my sites (30+) with Minify HTML plugin active:
When saving any post, page or CPT, the content will convert to Classic block. I suspect this is because of a recent WP core change and Minify HTML is now minifying the content in the editor.
Deactivating all plugins resolves the issue. Then activating Minify HTML causes the issue to reappear again.
For the time being I have deactivated Minify HTML on all my sites.
The recent Spanish topic “Comprime también el backend” appears to be the same issue as this: content is minified in the editor.
-
I can’t duplicate your issue. The Minify HTML plugin already checks
is_admin()
and doesn’t run minification if the user is an admin (which should be anytime in the admin console). I’m testing with WordPress v6.4.1, so it’s possible a fix corrected the problem. I do see a bug fixed in v6.4.1 having to do withwp_admin_notice()
, whichis_admin()
may rely on. If you’re not running v6.4.1, I would give it a try as that could be the issue.Looks like the issue can be reproduced in WP 6.4.1 with these steps:
- create a fresh site with default theme (I used Local)
- install and activate minify HTML with default settings
- install and activate Yoast SEO, you may skip/finish setup wizard, doesn’t matter
- create a new draft post with a cover block and paragraph “test” inside
- save draft
- observe content converting to classic block
Given that Yoast SEO is a very common plugin this is probably something that should be investigated. The issue does not seem to occur without Yoast SEO when using the default theme. Sorry I can’t pinpoint the issue further.
Thanks for looking into it.
Maybe I don’t understand what to be looking for in step 6. Not sure what classic block is. When I save the draft, it looks exactly the same as it did before I saved it. When I exit the post and edit it, it looks the same.
What should I be looking for that’s changing? As I don’t see anything different.
Also, the the Minify HTML plugin does nothing if you’re an admin. This code in the plugin will only allow MinifyHTML’s functions to run if the user is not an admin:
if?(?!is_admin()?)
Classic block is what WordPress uses when it sees markup that it can’t recognize as block content, eg. a <p> without a preceding block comment. Classic block has a gray bar above the content with the word “Classic” in it.
My steps to reproduce do appear to be a bit flaky. I’ll see if I can make it 100% reproducible. I still have to emphasize that many dozens of my clients reported this issue and after deactivating minify HTML they all reported the issue is resolved.
Here’s how I can make it happen 100% on a default install, default theme with nothing but Yoast SEO and minify HTML installed and activated:
- Create a new post
- Add cover block with a white background (any color will do)
- Inside the cover block add a paragraph “Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque ut condimentum mi, et maximus eros. Donec eu fringilla dui, dapibus ullamcorper metus.”
- Below the paragraph add buttons and justify center.
- Save draft and preview (a new tab opens)
- In the preview tab click Edit post
- In the editor click Save draft
- The content is converted to Classic block (gray bar with text “Classic” in it)
Notably without the preview step the issue may or may not happen. I did trigger it multiple times without previewing but not always. I can however always trigger it if I preview the new post first and then save the draft.
Here’s the markup in my test case (from editor Copy all blocks):
<!-- wp:cover {"overlayColor":"base-2","isDark":false,"layout":{"type":"constrained"}} --> <div class="wp-block-cover is-light"><span aria-hidden="true" class="wp-block-cover__background has-base-2-background-color has-background-dim-100 has-background-dim"></span><div class="wp-block-cover__inner-container"><!-- wp:paragraph {"align":"center","placeholder":"Write title…","fontSize":"large"} --> <p class="has-text-align-center has-large-font-size">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque ut condimentum mi, et maximus eros. Donec eu fringilla dui, dapibus ullamcorper metus. </p> <!-- /wp:paragraph --> <!-- wp:buttons {"layout":{"type":"flex","justifyContent":"center"}} --> <div class="wp-block-buttons"><!-- wp:button --> <div class="wp-block-button"><a class="wp-block-button__link wp-element-button">Button</a></div> <!-- /wp:button --></div> <!-- /wp:buttons --></div></div> <!-- /wp:cover -->
Seems the source of this problem is a WordPress “bug” that’s been reported many times but there doesn’t seem to be a way to fix it.
Basically, the block editor uses the REST API which doesn’t know if the user is an admin or not. Not sure why the REST API doesn’t know that key state (would be easy to have that as part of the request payload or to be checked at validation). But in any case, admin state is not known. Further, even though there’s been numerous bug reports, it’s been determined that it’s unfixable in the WordPress core.
This bug report best discusses the issue:
https://github.com/WordPress/gutenberg/issues/51090
There’s some code in the above bug report that looks promising to resolve the problem with the plugin. I’ll see if it works. But, it’s very concerning that WordPress has parts of the admin console that no longer know if it’s in the admin state or not.
is_admin()
has been a core function to detect this state, and it’s no longer a valid check.I have tripped in that “bug” when solving another issue. I was going to suggest checking for REST_REQUEST but didn’t as I wasn’t sure if that would be a proper fix. I believe the semantics are something along the lines of “REST request is not part of admin pages, so is_admin() should return false” even though the request is made in admin pages.
Thanks for looking into this issue.
To test the fix, if you could go into the Tools>Plugin File Editor and select the Minify HTML plugin. Around line 38 the line should be:
if ( !is_admin() )
If you could change it to the following
if ( !is_admin() && !( defined( 'REST_REQUEST' ) && REST_REQUEST && 'edit' === $_GET['context'] ) )
And Update File. Then test to see if the bug no longer exists.
Thanks
This turned out to be harder to fix than I expected.
The proposed change from the github issue doesn’t fix the issue as the check on line 38 is outside the init action and REST_REQUEST is probably not defined yet.
Also, I don’t think the ‘edit’ context will ever be true when saving a draft or updating a post. I did spot ‘view’ and ‘edit’ contexts when refreshing the editor and while editing though.
I then tried checking for only REST_REQUEST but that also failed when checked too early. It seems to fail even if checking right before ob_start(‘teckel_minify_html_output’).
It follows that the REST check needs to happen as late as possible.
So I did some logging to find out how many times the minify function runs and without any changes it looks like the minify function can run up to 10 times when refreshing the editor and 3-5 times when saving a post. Didn’t test without Yoast so that might contribute.
I then made a helper function that can be run in the init hook (to avoid buffering unnecessarily) and also again in the output buffer callback (to avoid minifying and when we do, only do it once):
function teckel_should_skip_minifying() { /* Bail if CLI */ if ( defined( 'WP_CLI' ) && WP_CLI ) { error_log( 'BAIL - WP_CLI true' ); return true; } /* Bail if admin pages */ if ( is_admin() ) { error_log( 'BAIL - is_admin() true' ); return true; } /* Bail if REST REQUEST */ if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) { error_log( 'BAIL - REST request' ); return true; } /* Bail if any context */ if ( isset( $_GET['context'] ) ) { error_log( 'BAIL - context set to ' . $_GET['context'] ); return true; } /* Nothing stopping us from minifying */ error_log( 'teckel_should_skip_minifying() - return false' ); return false; }
I then call this helper function like this:
function teckel_init_minify_html() { if ( teckel_should_skip_minifying() ) { return; } ...
and:
function teckel_minify_html_output($buffer) { if ( teckel_should_skip_minifying() ) { return $buffer; } ...
Notably even now, just refreshing the editor, I still see in the logs that the plugin minifies at least once. This could be Yoast or something else doing something with the content. But at least the content is not converted to a classic block anymore.
All of those checks need to be separate or this doesn’t work. You will find all conditions printing something in the logs multiple times by just refreshing the editor.
I wish there was a cleaner fix but this finally seems to work. Let me know if you find a cleaner way.
Hey,
I have exactly the same issue with WP 6.4.3 and minifyHTML 2.1.9.
With the last solution of @villekautto : in which file did you add this ?
If you have other solution, i’m in !
??The issue is that WordPress no longer knows if it’s an admin in the dashboard or visitor viewing the website as it’s using an API that doesn’t know the user’s access. Therefore, it can’t disable plug-ins (like Minify HTML) when it did before. This is a current “limitation” (or bug) with WordPress. As many are having issues with this, the hope is that WordPress will adopt a more appropriate API route which validates the user’s access level (which kind of seems important).
I’ve tried work-arounds, but none have been successful at this point.
@hgaugenot I have deactivated the plugin from all my sites for the time being. The fix I made worked for me in my use cases but it is not a proper fix so I can’t recommend it as it is. It is probably best to wait for a WordPress fix like @teckel said.
Hello there, as I’m facing the same problem and I like the plugin for it’s simplicity, I was playing around a bit with the ChatGPT 4 and after several tries it seems this updated function teckel_init_minify_html() works as it applies minification only on frontend HTML:
function teckel_init_minify_html() {
if (is_admin() || (defined(‘REST_REQUEST’) && REST_REQUEST) || (defined(‘DOING_AJAX’) && DOING_AJAX)) {
return;
}
$minify_html_active = get_option(‘minify_html_active’);
if ($minify_html_active != ‘no’) {
ob_start(‘teckel_minify_html_output’);
}
}
add_action(‘template_redirect’, ‘teckel_init_minify_html’);@jirsbek where do i add the code to? it seems when i add it in code snippets, it shows to not redeclare the same function again. So, I guess then we need to update the code in the plugin file only? but that would mean everytime an update is made to the plugin, changes are flushed.
So what did you do?
- You must be logged in to reply to this topic.