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

Double gutenberg_ prefix given to some PHP functions during the build #40938

Closed
adamziel opened this issue May 9, 2022 · 6 comments · Fixed by #60288
Closed

Double gutenberg_ prefix given to some PHP functions during the build #40938

adamziel opened this issue May 9, 2022 · 6 comments · Fixed by #60288
Assignees
Labels
Developer Experience Ideas about improving block and theme developer experience [Status] In Progress Tracking issues with work in progress [Type] Bug An existing feature does not function as intended [Type] Build Tooling Issues or PRs related to build tooling

Comments

@adamziel
Copy link
Contributor

adamziel commented May 9, 2022

Description

Add the following code to packages/block-library/blocks/navigation.php and run the build:

function block_core_navigation_get_post_ids( ) {
}

function block_core_navigation_get_post_ids_from_block( ) {
}

It gets bundled in build/block-library/blocks/navigation.php as:

function gutenberg_block_core_navigation_get_post_ids( ) {
}

function gutenberg_gutenberg_block_core_navigation_get_post_ids_from_block( ) {
}

This is caused by the following webpack transform:

transform: ( content ) => {
const prefix = 'gutenberg_';
content = content.toString();
// Within content, search and prefix any function calls from
// `prefixFunctions` list. This is needed because some functions
// are called inside block files, but have been declared elsewhere.
// So with the rename we can call Gutenberg override functions, but the
// block will still call the core function when updates are back ported.
content = content.replace(
new RegExp( prefixFunctions.join( '|' ), 'g' ),
( match ) => `${ prefix }${ match }`
);
// Within content, search for any function definitions. For
// each, replace every other reference to it in the file.
return (
Array.from(
content.matchAll(
/^\s*function ([^\(]+)/gm
)
)
.reduce( ( result, [ , functionName ] ) => {
// Prepend the Gutenberg prefix, substituting any
// other core prefix (e.g. "wp_").
return result.replace(
new RegExp( functionName, 'g' ),
( match ) =>
prefix +
match.replace( /^wp_/, '' )
);
}, content )
// The core blocks override procedure takes place in
// the init action default priority to ensure that core
// blocks would have been registered already. Since the
// blocks implementations occur at the default priority
// and due to WordPress hooks behavior not considering
// mutations to the same priority during another's
// callback, the Gutenberg build blocks are modified
// to occur at a later priority.
.replace(
/(add_action\(\s*'init',\s*'gutenberg_register_block_[^']+'(?!,))/,
'$1, 20'
)
);
},
noErrorOnMissing: true,
},

In short:

  1. The transform finds function block_core_navigation_get_post_ids
  2. It performs a naive str_replace to gutenberg_block_core_navigation_get_post_ids
  3. In the process, block_core_navigation_get_post_ids_from_block also gets affected
  4. Then, the transform acts on the block_core_navigation_get_post_ids_from_block separately

And we end up with a double prefix.

Initially seen in #40752 (comment)

Related: #40657

cc @spacedmonkey @gziolo @youknowriad @ellatrix @noisysocks @getdave

@adamziel adamziel added [Type] Bug An existing feature does not function as intended [Type] Build Tooling Issues or PRs related to build tooling Developer Experience Ideas about improving block and theme developer experience labels May 9, 2022
@adamziel
Copy link
Contributor Author

adamziel commented May 9, 2022

I initially thought of replacing function $name to function gutenberg_$name instead of $name to gutenberg_$name, but that would not handle cases like $post_ids = array_map( 'block_core_navigation_get_post_ids_from_block', iterator_to_array( $inner_blocks ) );.

The only other solution I can think if is checking each match for the presence of gutenberg_ prefix right before replacing. Otherwise, we'd need a PHP parser.

@noisysocks
Copy link
Member

Lol nice. Could we use a negative lookahead? Haven't tested it but something like this.

/^\s*function (?!gutenberg_)([^\(]+)/gm

@adamziel
Copy link
Contributor Author

adamziel commented May 10, 2022

@noisysocks that would work, we'd just have to stop precomputing all the matches first:

Array.from(
	content.matchAll(
		/^\s*function ([^\(]+)/gm
	)
)
	.reduce( ( result, [ , functionName ] ) => {
		// Prepend the Gutenberg prefix
	}, content )

And start matching and replacing in batches of one:

while ( true ) {
	const match = content.match(
		/^\s*function (?!gutenberg_)([^\(]+)/gm
	);
	if ( ! match ) break;
	// Prepend the Gutenberg prefix
}

@ockham
Copy link
Contributor

ockham commented Mar 28, 2024

Also happening to block_core_navigation_insert_hooked_blocks_into_rest_response (because it fully includes another function name, block_core_navigation_insert_hooked_blocks).

@ockham
Copy link
Contributor

ockham commented Mar 28, 2024

@noisysocks that would work, we'd just have to stop precomputing all the matches first [...] [a]nd start matching and replacing in batches of one: [...]

Alternatively, we might be able to keep the batch processing if we made sure we're only replacing full function names, i.e. tweak this part so that functionName needs to be followed by a non-alphanum, non-underscore:

new RegExp(
functionName,
'g'
),

Finally, a quick-and-dirty fix might be to remove gutenberg_ before adding gutenberg_ 😬

diff --git a/tools/webpack/blocks.js b/tools/webpack/blocks.js
index 080ee2e0124..329510e9fba 100644
--- a/tools/webpack/blocks.js
+++ b/tools/webpack/blocks.js
@@ -194,7 +194,7 @@ module.exports = [
 													( match ) =>
 														prefix +
 														match.replace(
-															/^wp_/,
+															/^(wp_|gutenberg_)/,
 															''
 														)
 												);

@adamziel
Copy link
Contributor Author

Moving the rewriting to PHP and using the built-in tokenizer would make this much easier.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Developer Experience Ideas about improving block and theme developer experience [Status] In Progress Tracking issues with work in progress [Type] Bug An existing feature does not function as intended [Type] Build Tooling Issues or PRs related to build tooling
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants