Guide

Hook reference

The configurator and its add-ons expose several hundred hooks — PHP actions and filters on the server, and JavaScript actions and filters in the browser. This section documents them, one page per plugin.

In this section

For the 3D viewer's Three.js scene — custom materials, shaders, animations and postprocessing — see The 3D runtime API, which covers a live object rather than a hook list.

PHP hooks

Ordinary WordPress actions and filters. Nothing special is required beyond loading your code before the hook fires, which for almost everything here means a plugin or a site plugin rather than a theme's functions.php.

php functions.php
add_filter( 'mkl_pc_choice_default_settings', function ( $fields ) {	// …	return $fields;}, 20 );
Register a PHP filter.

Remember the fourth argument to add_filter() and add_action() when a hook passes more than one value. Omitting it is the single most common reason a hook "does not work":

php functions.php
add_filter( 'mkl_pc_cart_item_choice', function ( $html, $choice, $layer ) {	return $html;}, 10, 3 ); // ← without the 3, $choice and $layer never arrive
Pass every argument through to the callback.

JavaScript hooks

The configurator uses @wordpress/hooks, the same API as the block editor, exposed at wp.hooks. Actions and filters work as they do in PHP, with one addition: every callback must be given a namespace as its second argument.

javascript custom.js
wp.hooks.addFilter(	'PC.fe.configurator.choice_data', // hook name	'my-plugin/choices',              // your namespace — required	function ( data ) {		return data;	});
Register a JavaScript filter with a namespace.

Enqueue your script with wp-hooks as a dependency, and nothing else:

php functions.php
add_action( 'wp_enqueue_scripts', function () {	wp_enqueue_script(		'my-plugin-configurator',		plugin_dir_url( __FILE__ ) . 'js/configurator.js',		array( 'wp-hooks' ),		'1.0.0',		true	);} );
Enqueue your script with wp-hooks as a dependency, and nothing else.

wp-hooks is tiny and always loads before the configurator, so your handlers are registered by the time anything fires. Depending on the configurator's own script handles instead ties your code to pages where the configurator happens to load.

Filters must return a value; a filter callback that returns nothing will blank whatever it was filtering.

Naming conventions

The prefix tells you where a hook lives and roughly what it does.

PrefixWhereNotes
mkl_pc_…PHPThe original convention. Most of the core hooks.
mkl_pc/…PHPNewer, path-style grouping — mkl_pc/order_created/…, mkl_pc/wc_cart_get_item_data/….
mkl/pc/…PHPA small number of older hooks, kept for compatibility.
tmpl-…PHPTemplate part hooks. They echo markup into an Underscore template rather than returning it.
PC.fe.…JSThe frontend configurator. fe is "front end".
PC.3d.…JSThe 3D viewer's own extension points.
PC.choices.…JSChoice selection logic, shared by admin and frontend.
mkl_pc.…JSA handful of data-loading events.

Add-ons follow the same scheme with their own segment — PC.fe.text-overlay.…, mkl_pc_extra_price_…, and so on.

Template hooks are different

Hooks whose name starts with tmpl- fire inside wp.template markup. They print, they do not return, and the content they print is Underscore template syntax evaluated later in the browser:

php functions.php
add_action( 'tmpl-pc-configurator-choice-item--after', function () { ?>	<# if ( data.my_field ) { #>		<span class="my-field">{{ data.my_field }}</span>	<# } #><?php } );
Template hooks are different.

{{ }} escapes, {{{ }}} does not, and <# #> is JavaScript. See Adding custom data to choices for a worked example.

Stability

Hooks marked Internal exist for the plugin's own use. They are documented because you will see them in the source, not because they are safe to build on — their arguments and firing order can change in any release. Everything else is intended for third-party use and treated as part of the public surface.

Where a hook name contains {$…}, the name is assembled at runtime from a setting key, a field id or similar. The page says what the variable part holds.