# Zactonz Number Plates for WooCommerce: Developers

> Sell made-to-order number plates. Shoppers configure a registration, see it drawn to scale as they type, and the order carries production-ready SVG artwork from the same renderer.

Page: https://developers.zactonz.com/wordpress/plugins/zactonz-number-plates-for-woocommerce/developers/

Complete documentation for this product: https://developers.zactonz.com/wordpress/plugins/zactonz-number-plates-for-woocommerce.md

Everything below is a WordPress filter. Register your callbacks from your own plugin and keep any files they need there, because anything inside this plugin's directory is replaced when it updates.

## Typefaces

`zctz_np_profile_faces` gives the typefaces a country profile may set a plate in, in preference order. The first face that measures every character and fits the plate wins, which reproduces the regulation's own Mittelschrift-then-Engschrift rule without the renderer knowing anything about Germany. A face that cannot measure a character is passed over for plates containing it rather than drawn with a glyph of zero width.

The usual reason to use it is FE-Engschrift for the longest German registrations, which is not bundled. A merchant licensed to use one adds it like this:

```php
add_filter(
	'zctz_np_profile_faces',
	function ( array $faces, string $profile_id ): array {
		if ( 'de' !== $profile_id ) {
			return $faces;
		}

		$faces[] = array(
			'family'  => 'FE-Engschrift',
			'path'    => '/absolute/path/to/engschrift.woff',
			'url'     => 'https://example.com/fonts/engschrift.woff',
			'metrics' => array( /* advance widths in font units */ ),
		);

		return $faces;
	},
	10,
	2
);
```

The metrics are the face's advance widths in font units. The plugin's source ships `tools/font-metrics.php`, which measures a WOFF or TrueType file and prints the array ready to paste. WOFF2 is refused, because its table stream is Brotli-compressed and PHP bundles no Brotli.

## Country profiles

`zctz_np_profiles` maps a profile identifier to its specification array, or to the path of a PHP file that returns one:

```php
add_filter( 'zctz_np_profiles', function ( array $registered ): array {
	$registered['at'] = __DIR__ . '/profiles/at-profile.php';

	return $registered;
} );
```

A profile is data: ordered fields with character classes, sizes in millimetres, colours, geometry and typefaces. One registry answers both which countries a merchant may pick and which one to load, so a country you add is genuinely usable rather than merely listed. Give the profile its font metrics and glyph outlines inline as arrays rather than naming a data file. A callback may build on a shipped profile by calling `Profile::get( 'de' )` inside the filter; the call is re-entrant and the filter runs once per request.

## Blocked letter sequences

`zctz_np_blocked_sequences` is the list of letter sequences refused on the Erkennungsnummer. The shipped list is a convention rather than a statute, because Germany's registration offices keep their own lists and they differ. Replace or extend it to match the office you deal with.

## Layouts

- `zctz_np_default_template` sets the layout for every product that names none, which saves setting it on each one.
- `zctz_np_templates` registers a layout of your own, and `zctz_np_render_template` renders it. All layouts collect the same fields with the same names and data attributes and share one stylesheet and one script, so a layout owns neither validation nor pricing and cannot drift from the others on either.

## Switching parts off

Six filters each switch off one part of the plugin: `zctz_np_load_admin`, `zctz_np_load_artwork`, `zctz_np_load_configurator`, `zctz_np_load_cart`, `zctz_np_load_pricing` and `zctz_np_load_rest`. Return false from one to leave that part unloaded.

## Removal

Define `ZCTZ_NP_REMOVE_DATA` as true in `wp-config.php` before deleting the plugin to remove the product settings as well. Orders are never touched.

## Store API

The configured plate is attached through `woocommerce_add_cart_item_data`, which WooCommerce's Store API applies as well. The add-item route carries the plate only for a form-encoded request; a JSON body is refused with "Choose a plate type". The cart and checkout blocks are unaffected because they only read the cart.
