TLDR: It's not mangled, it's raw JSON values that haven't been decoded, not intended for us humans. JSON decode first before use.
This happens in serialize_block_attributes
, the docblock explains why:
/**
...
* The serialized result is a JSON-encoded string, with unicode escape sequence
* substitution for characters which might otherwise interfere with embedding
* the result in an HTML comment.
...
*/
So this is done as an encoding measure to avoid attributes accidentally closing a HTML comment and breaking the format of the document.
Without this, a HTML comment inside a block attribute would break the block and the rest of the content afterwards.
But How Do I Stop The Mangling?!!!
No, it isn't mangled it's encoded! You're not meant to read it literally, it needs decoding first. It's encoding certain characters by replacing them with unicode escaped versions to prevent breakage.
It's the same as opening up a fibre optic cable and looking at what's being sent, you won't see webpages you'll see pulses of light, a computer has to decode and process it and turn it into human friendly information. It's the same here.
Proof 1
Lets take the original code block from the question, and add the following fixes:
- Wrap all in
<pre>
tags
- Use
esc_html
so we can see the tags properly
- Fix the
printf
by removing var_dump
and using var_export
with the second parameter so it returns rather than outputs
- Add a final test case where we re-parse and re-serialize 10 times to compare the final result with the original
function reparse_reserialize( string $content, int $loops = 10 ) : string {
$final_content = $content;
for ($x = 0; $x <= $loops; $x++) {
$blocks = parse_blocks( $final_content );
$final_content = serialize_blocks( $blocks );
}
return $final_content;
}
add_action(
'wp',
function() {
$p = get_post( 1 );
echo '<p>Original content:</p>';
echo '<pre>' . esc_html( var_export( $p->post_content, true ) ) . '</pre>';
$final = reparse_reserialize( $p->post_content );
echo '<p>10 parse and serialize loops later:</p>';
echo '<pre>' . esc_html( var_export( $final, true ) ) . '</pre>';
echo '<hr/>';
},
PHP_INT_MAX
);
Running that, we see that the content survived the process of being parsed and re-serialized 10 times. If mangling was occuring we would see progressively greater mangling occur
Proof 2
If we take the mangled markup:
\u003ch3\u003eWhat types of accommodation are available in xxxx?\u003c\/h3\u003e
Turn it into a JSON string, then decode it:
$json = '"\u003ch3\u003eWhat types of accommodation are available in xxxx?\u003c\/h3\u003e"';
echo '<pre>' . esc_html( json_decode( $json ) ) . '</pre>';
We get the original HTML:
<h3>What types of accommodation are available in xxxx?</h3>
So no mangling has taken place.
Summary
There is no mangling or corruption. It's just encoding the <
and >
to prevent breakage. JSON processors handle the unicode escape characters just fine.
If you are seeing these encoded characters in the block editor, then that is a bug, either in the block, or the ACF plugin. You should report it as such.
If you're seeing those encoded characters in your own work, run JSON decode before using the values. You can JSON encode if you want to serialize it back to the database. Remember, block attributes are normally stored as JSON inside a HTML comment, as long as it's valid JSON it should be ok when you decode it.
save
method of a block is for. Have you confirmed the block editor is unable to handle the reserialized data?<
and>
is used. btw if you're doing this because you want to modify the HTML markup in PHP of blocks rendered with javascript, then no, just no. You can't do that. Your blocks will show as invalid when you reopen the block editor and fail validation. However if you do not care about that, then I do not see the problem. Just JSON decode the result to decode the characters.