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
- Product Configurator — the core plugin, the large majority of the hooks.
- Advanced Description
- Conditional Logic
- Extra Price
- Form Fields
- Linked Product Stock Management
- Multiple Choice
- Save Your Design
- Text Overlay
- 3D Premium
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.
add_filter( 'mkl_pc_choice_default_settings', function ( $fields ) { // … return $fields;}, 20 );
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":
add_filter( 'mkl_pc_cart_item_choice', function ( $html, $choice, $layer ) { return $html;}, 10, 3 ); // ← without the 3, $choice and $layer never arrive
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.
wp.hooks.addFilter( 'PC.fe.configurator.choice_data', // hook name 'my-plugin/choices', // your namespace — required function ( data ) { return data; });
Enqueue your script with wp-hooks as a dependency, and nothing else:
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 );} );
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.
| Prefix | Where | Notes |
|---|---|---|
mkl_pc_… | PHP | The original convention. Most of the core hooks. |
mkl_pc/… | PHP | Newer, path-style grouping — mkl_pc/order_created/…, mkl_pc/wc_cart_get_item_data/…. |
mkl/pc/… | PHP | A small number of older hooks, kept for compatibility. |
tmpl-… | PHP | Template part hooks. They echo markup into an Underscore template rather than returning it. |
PC.fe.… | JS | The frontend configurator. fe is "front end". |
PC.3d.… | JS | The 3D viewer's own extension points. |
PC.choices.… | JS | Choice selection logic, shared by admin and frontend. |
mkl_pc.… | JS | A 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:
add_action( 'tmpl-pc-configurator-choice-item--after', function () { ?> <# if ( data.my_field ) { #> <span class="my-field">{{ data.my_field }}</span> <# } #><?php } );
{{ }} 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.